﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Вызов этой процедуры необходимо разместить в модуле сеанса в процедуре УстановкаПараметровСеанса
// согласно документации.
//
// Параметры:
//  ИменаПараметровСеанса - Массив
//                        - Неопределено - имена параметров сеанса для инициализации.
//                                         Массив устанавливаемых идентификаторов параметров сеанса,
//                                         которые нужно инициализировать, если обработчик вызывается
//                                         перед использованием неинициализированных параметров сеанса.
//                                         Неопределено, если обработчик события вызывается системой при начале сеанса.
//
// Возвращаемое значение:
//  Массив - имена параметров сеанса, значения которых были успешно установлены.
//
Функция УстановкаПараметровСеанса(ИменаПараметровСеанса) Экспорт
	
	// Параметры сеанса, инициализация которых требует обращения к одним и тем же данным
	// следует инициализировать сразу группой. Для того, чтобы избежать их повторной инициализации,
	// имена уже установленных параметров сеанса сохраняются в массиве УстановленныеПараметры.
	УстановленныеПараметры = Новый Массив;
	
#Если НЕ МобильныйАвтономныйСервер Тогда
	
	Если ИменаПараметровСеанса <> Неопределено
	   И ИменаПараметровСеанса.Найти("ПараметрыКлиентаНаСервере") <> Неопределено Тогда
		
		ПараметрыСеанса.ПараметрыКлиентаНаСервере = Новый ФиксированноеСоответствие(Новый Соответствие);
		УстановленныеПараметры.Добавить("ПараметрыКлиентаНаСервере");
		Если ИменаПараметровСеанса.Количество() = 1 Тогда
			Возврат УстановленныеПараметры;
		КонецЕсли;
	КонецЕсли;
	
	Если ИменаПараметровСеанса = Неопределено Тогда
		Если ПараметрыСеанса.ПараметрыКлиентаНаСервере.Количество() = 0 Тогда
			НезаполненныеПараметрыКлиента = Новый Соответствие;
			НезаполненныеПараметрыКлиента.Вставить("ПервыйСерверныйВызовВыполнен",
				?(ТекущийРежимЗапуска() = Неопределено, Неопределено, Ложь));
			НезаполненныеПараметрыКлиента.Вставить("СостояниеДоВызоваАвторизоватьТекущегоПользователя", Истина);
			ПараметрыСеанса.ПараметрыКлиентаНаСервере = Новый ФиксированноеСоответствие(НезаполненныеПараметрыКлиента);
		КонецЕсли;
		Справочники.ВерсииРасширений.УстановкаПараметровСеанса(ИменаПараметровСеанса, УстановленныеПараметры);
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
			МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
			МодульМультиязычностьСервер.УстановкаПараметровСеанса(ИменаПараметровСеанса, УстановленныеПараметры);
		КонецЕсли;
		
		// При установке соединения с информационной базой до вызова всех остальных обработчиков.
		ПередЗапускомПрограммы();
		Возврат УстановленныеПараметры;
	КонецЕсли;
	
	Если Справочники.ИдентификаторыОбъектовМетаданных.ВсеПараметрыСеансаУстановлены(
			ИменаПараметровСеанса, УстановленныеПараметры) Тогда
		Возврат УстановленныеПараметры;
	КонецЕсли;
	
	Если ИменаПараметровСеанса.Найти("КлючДанныхПовторногоИспользования") <> Неопределено Тогда
		ПараметрыСеанса.КлючДанныхПовторногоИспользования = Новый УникальныйИдентификатор;
		УстановленныеПараметры.Добавить("КлючДанныхПовторногоИспользования");
	КонецЕсли;
	
	Справочники.ВерсииРасширений.УстановкаПараметровСеанса(ИменаПараметровСеанса, УстановленныеПараметры);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
		МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
		МодульМультиязычностьСервер.УстановкаПараметровСеанса(ИменаПараметровСеанса, УстановленныеПараметры);
	КонецЕсли;
	
	Если ИменаПараметровСеанса.Найти("БуферОбмена") <> Неопределено Тогда
		ПараметрыСеанса.БуферОбмена = Новый ФиксированнаяСтруктура(Новый Структура("Источник, Данные"));
		УстановленныеПараметры.Добавить("БуферОбмена");
	КонецЕсли;
	
	Обработчики = Новый Соответствие;
	ИнтеграцияПодсистемБСП.ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики);
	
	ОбработчикиСобственные = Новый Соответствие;
	ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса(ОбработчикиСобственные);
	Для Каждого Запись Из ОбработчикиСобственные Цикл
		Обработчики.Вставить(Запись.Ключ, Запись.Значение);
	КонецЦикла;
	
	ВыполнитьОбработчикиУстановкиПараметровСеанса(ИменаПараметровСеанса, Обработчики, УстановленныеПараметры);
	
	ИнтеграцияПодсистемБСП.ПриУстановкеПараметровСеанса(ИменаПараметровСеанса);
	
#КонецЕсли
	
	Возврат УстановленныеПараметры;
	
КонецФункции

#Если НЕ МобильныйАвтономныйСервер Тогда

// Возвращает признак того, является ли конфигурация базовой.
// Базовые версии конфигураций могут иметь программные ограничения, действие которых
// можно предусмотреть с помощью этой функции.
// Конфигурация считается базовой, если в ее имени есть термин "Базовая",
// например, "УправлениеТорговлейБазовая".
//
// Возвращаемое значение:
//   Булево - Истина, если конфигурация - базовая.
//
Функция ЭтоБазоваяВерсияКонфигурации() Экспорт
	
	ЭтоБазоваяВерсияКонфигурации = СтрНайти(ВРег(Метаданные.Имя), НСтр("ru = 'БАЗОВАЯ'")) > 0;
	ОбщегоНазначенияПереопределяемый.ПриОпределенииПризнакаЭтоБазоваяВерсияКонфигурации(ЭтоБазоваяВерсияКонфигурации);
	
	Возврат ЭтоБазоваяВерсияКонфигурации;
	
КонецФункции

// Возвращает признак того, что выполнение происходит на учебной платформе.
// Используется, когда нужно поддержать работу кода, который зависит
// от ограничений учебной версии платформы.
//
// Возвращаемое значение:
//   Булево - Истина, если выполнение происходит на учебной платформе.
//
Функция ЭтоУчебнаяПлатформа() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();

	Попытка
		ПользовательОС = ТекущийПользователь.ПользовательОС;
	Исключение
		// В учебной версии платформы недоступно получение свойства ПользовательОС.
		Возврат Истина;
	КонецПопытки;
	Возврат Ложь;
	
КонецФункции

// Обновляет кэши свойств метаданных, позволяющие ускорить
// открытие сеанса, а также обновление ИБ, особенно в модели сервиса.
// Их обновление происходит до обновления ИБ.
//
// Для использования в других библиотеках и конфигурациях.
//
Процедура ОбновитьВсеПараметрыРаботыПрограммы() Экспорт
	
	РегистрыСведений.ПараметрыРаботыПрограммы.ОбновитьВсеПараметрыРаботыПрограммы();
	
КонецПроцедуры

// Возвращает номер версии "Библиотеки стандартных подсистем" (БСП),
// встроенной в конфигурацию.
//
// Возвращаемое значение:
//  Строка - версия БСП, например "1.0.1.1".
//
Функция ВерсияБиблиотеки() Экспорт
	
	Возврат СтандартныеПодсистемыПовтИсп.ОписанияПодсистем().ПоИменам["СтандартныеПодсистемы"].Версия;
	
КонецФункции

// Получает уникальный идентификатор информационной базы,
// с помощью которого можно различать различные экземпляры информационных баз,
// например, при сборе статистики или в механизмах внешнего управления базами.
// Если идентификатор не заполнен, то его значение автоматически устанавливается и возвращается.
//
// Идентификатор хранится в константе ИдентификаторИнформационнойБазы.
// Константа ИдентификаторИнформационнойБазы не должна входить в составы планов обмена, чтобы иметь
// различные значения в каждой информационной базе (узле РИБ).
//
// Возвращаемое значение:
//  Строка - идентификатор информационной базы.
//
Функция ИдентификаторИнформационнойБазы() Экспорт
	
	ИдентификаторИнформационнойБазы = Константы.ИдентификаторИнформационнойБазы.Получить();
	
	Если ПустаяСтрока(ИдентификаторИнформационнойБазы) Тогда
		ИдентификаторИнформационнойБазы = Строка(Новый УникальныйИдентификатор());
		
		УстановитьОтключениеБезопасногоРежима(Истина);
		УстановитьПривилегированныйРежим(Истина);
		
		Константы.ИдентификаторИнформационнойБазы.Установить(ИдентификаторИнформационнойБазы);
		
		УстановитьПривилегированныйРежим(Ложь);
		УстановитьОтключениеБезопасногоРежима(Ложь);
	КонецЕсли;
	
	Возврат ИдентификаторИнформационнойБазы;
	
КонецФункции

// Возвращает сохраненные в информационной базы параметры администрирования.
// Предназначена для использования в механизмах, требующих для свой работы
// ввода параметров администрирования информационной базы и/или кластера серверов.
// Например, блокировка установки соединений с информационной базой.
// См. так же УстановитьПараметрыАдминистрирования.
//
// Возвращаемое значение:
//  Структура - содержит свойства двух структур
//              АдминистрированиеКластераКлиентСервер.ПараметрыАдминистрированияКластера 
//              и АдминистрированиеКластераКлиентСервер.ПараметрыАдминистрированияИнформационнойБазыКластера.
//              При этом поля, содержащие пароли, возвращаются пустыми. Если параметры администрирования
//              не были ранее сохранены при помощи функции УстановитьПараметрыАдминистрирования,
//              то будут возвращены автоматически вычисленные параметры администрирования по умолчанию.
//
Функция ПараметрыАдминистрирования() Экспорт
	
	Если ОбщегоНазначения.РазделениеВключено()
	   И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
			ВызватьИсключение НСтр("ru = 'Недостаточно прав для выполнения операции'");
		КонецЕсли;
	Иначе
		Если Не Пользователи.ЭтоПолноправныйПользователь(, Истина) Тогда
			ВызватьИсключение НСтр("ru = 'Недостаточно прав для выполнения операции'");
		КонецЕсли;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	ПараметрыАдминистрированияИБ = Константы.ПараметрыАдминистрированияИБ.Получить().Получить();
	ПараметрыАдминистрированияПоУмолчанию = ПараметрыАдминистрированияПоУмолчанию();
	
	Если ТипЗнч(ПараметрыАдминистрированияИБ) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(ПараметрыАдминистрированияПоУмолчанию, ПараметрыАдминистрированияИБ);
	КонецЕсли;
	ПараметрыАдминистрированияИБ = ПараметрыАдминистрированияПоУмолчанию;
	
	Если Не ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
		ПрочитатьПараметрыИзСтрокиСоединения(ПараметрыАдминистрированияИБ);
	КонецЕсли;
	
	Возврат ПараметрыАдминистрированияИБ;
	
КонецФункции

// Сохраняет параметры администрирования информационной базы и кластера серверов.
// При сохранении поля, содержащие пароли, будут очищены в целях безопасности.
//
// Параметры:
//  ПараметрыАдминистрированияИБ - см. ПараметрыАдминистрирования
//
// Пример:
//  ПараметрыАдминистрирования = СтандартныеПодсистемыСервер.ПараметрыАдминистрирования();
//  // Вывод параметров администрирования администратору для подтверждения корректности и ввода паролей.
//  // Далее выполнение действий, связанных с подключением к кластеру серверов.
//  СтандартныеПодсистемыСервер.ПараметрыАдминистрирования(ПараметрыАдминистрирования);
//
Процедура УстановитьПараметрыАдминистрирования(ПараметрыАдминистрированияИБ) Экспорт
	
	ПараметрыАдминистрированияИБ.ПарольАдминистратораКластера = "";
	ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы = "";
	Константы.ПараметрыАдминистрированияИБ.Установить(Новый ХранилищеЗначения(ПараметрыАдминистрированияИБ));
	
КонецПроцедуры

// Устанавливает представление поля Дата в списках, содержащих реквизит с составом даты Дата и время.
// Подробнее см. стандарт "Поле "Дата" в списках".
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения - форма со списком.
//   ПолноеИмяРеквизита - Строка - полный путь к реквизиту типа "Дата" в формате "<ИмяСписка>.<ИмяПоля>".
//   ИмяЭлемента - Строка - имя элемента формы, связанного с реквизитом списка типа "Дата".
//
// Пример:
//
//	Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//		СтандартныеПодсистемыСервер.УстановитьУсловноеОформлениеПоляДата(ЭтотОбъект);
//
Процедура УстановитьУсловноеОформлениеПоляДата(Форма, 
	ПолноеИмяРеквизита = "Список.Дата", ИмяЭлемента = "Дата") Экспорт
	
	ОбщегоНазначенияКлиентСервер.ПроверитьПараметр(
		"СтандартныеПодсистемыСервер.УстановитьУсловноеОформлениеПоляДата",
		"ЭтотОбъект", 
		Форма, 
		Тип("ФормаКлиентскогоПриложения"));
	
	ЧастиПолногоИмени = СтрРазделить(ПолноеИмяРеквизита, ".");
	
	Если ЧастиПолногоИмени.Количество() <> 2 Тогда 
		// Недопустимое значение параметра ПолноеИмяРеквизита.
		// Имя реквизита должно быть в формате ""<ИмяСписка>.<ИмяПоля>""'");
		Возврат;
	КонецЕсли;
	
	ИмяСписка = ЧастиПолногоИмени[0];
	РеквизитСписок = Форма[ИмяСписка];
	
	Если ТипЗнч(РеквизитСписок) = Тип("ДинамическийСписок") Тогда 
		// ДинамическийСписок позволяет установить условное оформление с помощью собственного компоновщика.
		// При этом параметр ИмяЭлемента игнорируется, потому что компоновщик динамического списка
		// не знает как будут отображены реквизиты списка, потому путем к реквизиту и значения отбора и оформления 
		// является имя реквизита динамического списка.
		УсловноеОформление = РеквизитСписок.УсловноеОформление;
		ПутьКРеквизиту = ЧастиПолногоИмени[1];
		ИмяОформляемогоПоля = ПутьКРеквизиту;
	Иначе 
		// Остальные списки, например, ДанныеФормыДерево:
		// не имеют собственного компоновщика, потому используют компоновщик самой формы.
		УсловноеОформление = Форма.УсловноеОформление;
		ПутьКРеквизиту = ПолноеИмяРеквизита;
		ИмяОформляемогоПоля = ИмяЭлемента;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(УсловноеОформление.ИдентификаторПользовательскойНастройки) Тогда
		УсловноеОформление.ИдентификаторПользовательскойНастройки = "ОсновноеОформление";
	КонецЕсли;
	
	// Представление даты.
	ЭлементОформления = УсловноеОформление.Элементы.Добавить();
	ЭлементОформления.Использование = Истина;
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Формат", "ДЛФ=D");
	
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяОформляемогоПоля);
	
	// Представление даты сегодня.
	ЭлементОформления = УсловноеОформление.Элементы.Добавить();
	ЭлементОформления.Использование = Истина;
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Формат", НСтр("ru = 'ДФ=ЧЧ:мм'"));
	
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяОформляемогоПоля);
	
	ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных(ПутьКРеквизиту);
	ЭлементОтбора.ВидСравнения   = ВидСравненияКомпоновкиДанных.БольшеИлиРавно;
	ЭлементОтбора.ПравоеЗначение = Новый СтандартнаяДатаНачала(ВариантСтандартнойДатыНачала.НачалоЭтогоДня);
	
	ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных(ПутьКРеквизиту);
	ЭлементОтбора.ВидСравнения   = ВидСравненияКомпоновкиДанных.Меньше;
	ЭлементОтбора.ПравоеЗначение = Новый СтандартнаяДатаНачала(ВариантСтандартнойДатыНачала.НачалоСледующегоДня);
	
КонецПроцедуры

// Получает настройку необходимости выводить подтверждение при завершении работы программы
// для текущего пользователя. Предназначена для использования в форме персональных настроек
// пользователя. Пример использования см. в общей форме _ДемоМоиНастройки.
// 
// Возвращаемое значение:
//   Булево - если Истина, то пользователю при закрытии программы будет показано
//            окно с подтверждением завершения сеанса.
// 
Функция ЗапрашиватьПодтверждениеПриЗавершенииПрограммы() Экспорт
	
	Результат = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"ОбщиеНастройкиПользователя", 
		"ЗапрашиватьПодтверждениеПриЗавершенииПрограммы");
	
	Если Результат = Неопределено Тогда
		Результат = ОбщегоНазначения.ОбщиеПараметрыБазовойФункциональности().ЗапрашиватьПодтверждениеПриЗавершенииПрограммы;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращает описания форматов сохранения табличного документа.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * ТипФайлаТабличногоДокумента - ТипФайлаТабличногоДокумента - значение, соответствующее формату;
//   * Ссылка - ПеречислениеСсылка.ФорматыСохраненияОтчетов      - ссылка на метаданные, где хранится представление;
//   * Представление - Строка - представление типа файла (заполняется из перечисления);
//   * Расширение    - Строка - тип файла для операционной системы;
//   * Картинка      - Картинка - картинка формата.
//
Функция НастройкиФорматовСохраненияТабличногоДокумента() Экспорт
	
	ТаблицаФорматов = Новый ТаблицаЗначений;
	
	ТаблицаФорматов.Колонки.Добавить("ТипФайлаТабличногоДокумента", Новый ОписаниеТипов("ТипФайлаТабличногоДокумента"));
	ТаблицаФорматов.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("ПеречислениеСсылка.ФорматыСохраненияОтчетов"));
	ТаблицаФорматов.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
	ТаблицаФорматов.Колонки.Добавить("Расширение", Новый ОписаниеТипов("Строка"));
	ТаблицаФорматов.Колонки.Добавить("Картинка", Новый ОписаниеТипов("Картинка"));

	// Документ PDF (.pdf)
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокументаPDF();
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.PDF;
	НовыйФормат.Расширение = "pdf";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматPDF;
	НовыйФормат.Представление = ПредставлениеТипаФайлаТабличногоДокументаPDF();
	
	// Табличный документ (.mxl)
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.MXL;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.MXL;
	НовыйФормат.Расширение = "mxl";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматMXL;
	
	// Лист Microsoft Excel 2007 (.xlsx)
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.XLSX;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.XLSX;
	НовыйФормат.Расширение = "xlsx";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматExcel2007;

	// Лист Microsoft Excel 97-2003 (.xls)
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.XLS;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.XLS;
	НовыйФормат.Расширение = "xls";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматExcel;

	// Электронная таблица OpenDocument (.ods).
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.ODS;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.ODS;
	НовыйФормат.Расширение = "ods";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматOpenOfficeCalc;
	
	// Документ Word 2007 (.docx)
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.DOCX;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.DOCX;
	НовыйФормат.Расширение = "docx";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматWord2007;
	
	// Веб-страница (.html)
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.HTML5;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.HTML;
	НовыйФормат.Расширение = "html";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматHTML;
	
	// Текстовый документ UTF-8 (.txt).
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.TXT;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.TXT;
	НовыйФормат.Расширение = "txt";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматTXT;
	
	// Текстовый документ ANSI (.txt).
	НовыйФормат = ТаблицаФорматов.Добавить();
	НовыйФормат.ТипФайлаТабличногоДокумента = ТипФайлаТабличногоДокумента.ANSITXT;
	НовыйФормат.Ссылка = Перечисления.ФорматыСохраненияОтчетов.ANSITXT;
	НовыйФормат.Расширение = "txt";
	НовыйФормат.Картинка = БиблиотекаКартинок.ФорматTXT;
	
	Для Каждого ФорматСохранения Из ТаблицаФорматов Цикл
		Если Не ЗначениеЗаполнено(ФорматСохранения.Представление) Тогда
			ФорматСохранения.Представление = Строка(ФорматСохранения.Ссылка);
		КонецЕсли;
	КонецЦикла;
		
	Возврат ТаблицаФорматов;
	
КонецФункции

// Возвращает версию режима совместимости в формате нумерации редакций и версий, например, 8.3.15.0.
//
// Возвращаемое значение:
//   Строка - версия режима совместимости в формате нумерации редакций и версий.
//
Функция ВерсияРежимаСовместимости() Экспорт 
	
	Если Метаданные.РежимСовместимости = Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда 
		
		Информация = Новый СистемнаяИнформация;
		Возврат Информация.ВерсияПриложения;
		
	КонецЕсли;
	
	ОписаниеРежимаСовместимости = СтрРазделить(Метаданные.РежимСовместимости, "_");
	Символов = СтрДлина(ОписаниеРежимаСовместимости[0]);
	
	НомерРедакции = "";
	
	Для НомерСимвола = 1 По Символов Цикл 
		
		ТекущийСимвол = Сред(ОписаниеРежимаСовместимости[0], НомерСимвола, 1);
		
		Если СтрНайти("0123456789", ТекущийСимвол) > 0 Тогда 
			НомерРедакции = НомерРедакции + ТекущийСимвол;
		КонецЕсли;
		
	КонецЦикла;
	
	ОписаниеРежимаСовместимости.Установить(0, НомерРедакции);
	
	Для Индекс = ОписаниеРежимаСовместимости.Количество() По 3 Цикл 
		ОписаниеРежимаСовместимости.Добавить("0");
	КонецЦикла;
	
	Возврат СтрСоединить(ОписаниеРежимаСовместимости, ".");
	
КонецФункции

#Область УстаревшиеПроцедурыИФункции

// Устарела. Веб-клиент более не поддерживает конфигурации, которые используют интерфейс версии 8.2.
// При работе в веб-клиенте отключена возможность переключения интерфейса 
// между интерфейсом версии 8.2 и интерфейсом Такси.
//
// Устанавливает жирное оформление шрифта заголовков групп формы для их корректного отображения в интерфейсе 8.2.
// В интерфейсе "Такси" заголовки групп с обычным выделением и без выделения выводятся большим шрифтом.
// В интерфейсе 8.2 такие заголовки выводятся как обычные надписи и не ассоциируются с заголовками.
// Эта функция предназначена для визуального выделения (жирным шрифтом) заголовков групп в режиме интерфейса 8.2.
//
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - форма для изменения шрифта заголовков групп;
//  ИменаГрупп - Строка - список имен групп формы, разделенных запятыми. Если имена групп не указаны,
//                        то оформление будет применено ко всем группам на форме.
//
// Пример:
//  Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//    СтандартныеПодсистемыСервер.УстановитьОтображениеЗаголовковГрупп(ЭтотОбъект);
//
Процедура УстановитьОтображениеЗаголовковГрупп(Форма, ИменаГрупп = "") Экспорт
	
	// Ничего не выполняется.
	
КонецПроцедуры

#КонецОбласти

// Возвращает признак необходимости показа всплывающего уведомления об установленных
// обновлениях программы - динамическом обновлении программы, новых патчей и расширений.
//
// Возвращаемое значение:
//  Булево - если Истина, то всплывающие уведомления включены.
//
Функция ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы() Экспорт
	
	Возврат ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммыДляПользователя();
	
КонецФункции

#Область ДляВызоваИзДругихПодсистем

// Вызывается из регламентного задания для отправки серверного оповещения клиентским сеансам.
// Смотри также СтандартныеПодсистемыКлиент.ПриПолученииСерверногоОповещения.
//
// Вызов выполняется в привилегированном режиме с учетом истечения периода, указанного для оповещения.
// Смотри ОбщегоНазначенияПереопределяемый.ПриДобавленииСерверныхОповещений.
//
// Параметры:
//  ИмяОповещения - Строка - смотри СерверныеОповещения.НовоеСерверноеОповещение.Имя
//  ВариантыПараметров - Массив из Структура:
//   * Параметры - Произвольный - смотри СерверныеОповещения.НовоеСерверноеОповещение.Параметры
//   * Адресаты - Соответствие из КлючИЗначение:
//      ** Ключ - УникальныйИдентификатор - идентификатор пользователя ИБ
//      ** Значение - Массив из см. СерверныеОповещения.КлючСеанса
//
// Пример:
//	Если ИмяОповещения <> "СтандартныеПодсистемы.ЗавершениеРаботыПользователей.БлокировкаСеансов" Тогда
//		Возврат;
//	КонецЕсли;
//	ПараметрыБлокировкиСеансов = ПараметрыБлокировкиСеансов(Истина);
//	Если ПараметрыБлокировкиСеансов.Установлена Тогда
//		СерверныеОповещения.ОтправитьСерверноеОповещение(ИмяОповещения,
//			ПараметрыБлокировкиСеансов, Неопределено);
//	КонецЕсли;
//
Процедура ПриОтправкеСерверногоОповещения(ИмяОповещения, ВариантыПараметров) Экспорт
	
	Если ИмяОповещения = "СтандартныеПодсистемы.БазоваяФункциональность.ФункциональныеОпцииИзменены" Тогда
		ПриОтправкеСерверногоОповещенияФункциональныеОпцииИзменены(ИмяОповещения, ВариантыПараметров);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#КонецЕсли

#КонецОбласти

#Если НЕ МобильныйАвтономныйСервер Тогда

#Область СлужебныйПрограммныйИнтерфейс

// Отправляет оповещение всем сеансам об устаревании повторно используемых значений.
// 
// Параметры:
//  ОтправитьСразу - см. СерверныеОповещения.ОтправитьСерверноеОповещение.ОтправитьСразу
//
Процедура ОповеститьВсеСеансыОбУстареванииПовторноИспользуемыхЗначений(ОтправитьСразу = Ложь) Экспорт
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	СерверныеОповещения.ОтправитьСерверноеОповещение(
		"СтандартныеПодсистемы.БазоваяФункциональность.ПовторноИспользуемыеЗначенияУстарели",
		"",
		Неопределено,
		ОтправитьСразу);
	
	УстановитьПривилегированныйРежим(Ложь);
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Дополнительная базовая функциональность для анализа параметров клиента на сервере.

// Параметры:
//  ВызыватьИсключение - Булево - вызывать исключение, если параметры не инициализированы.
//
// Возвращает пустое фиксированное соответствие, если ТекущийРежимЗапуска() = Неопределено.
//
// Возвращаемое значение:
//  ФиксированноеСоответствие из КлючИЗначение:
//   * Ключ - Строка - "ПараметрЗапуска", "СтрокаСоединенияИнформационнойБазы"
//   * Значение - Строка
//
Функция ПараметрыКлиентаНаСервере(ВызыватьИсключение = Истина) Экспорт
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	ПараметрыКлиента = ПараметрыСеанса.ПараметрыКлиентаНаСервере;
	УстановитьПривилегированныйРежим(Ложь);
	УстановитьОтключениеБезопасногоРежима(Ложь);
	
	Если Не ВызыватьИсключение
	 Или ТекущийРежимЗапуска() = Неопределено
	   И ПараметрыКлиента.Получить("ПервыйСерверныйВызовВыполнен") = Неопределено
	 Или ПараметрыКлиента.Получить("ПервыйСерверныйВызовВыполнен") = Истина Тогда
		
		Возврат ПараметрыКлиента;
	КонецЕсли;
	
	Если ТекущийРежимЗапуска() <> Неопределено Тогда
		// Сброс клиентских кэшей для обращения к серверу при обращении к параметрам работы клиента,
		// чтобы при этом перезаполнились параметры клиента на сервере.
		ОбновитьПовторноИспользуемыеЗначения();
	КонецЕсли;
	
	ПриЗапуске = ПараметрыКлиента.Получить("ПервыйСерверныйВызовВыполнен") = Ложь;
	
	Если ПриЗапуске Тогда
		КомментарийДляЖурналаРегистрацииБезСтекаВызовов = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Недопустимое обращение к неинициализированным параметрам клиента на сервере.
			           |Вероятно, вызов выполнен преждевременно до завершения инициализации в %1.'",
			     ОбщегоНазначения.КодОсновногоЯзыка()),
			     "СтандартныеПодсистемыКлиент.ПередНачаломРаботыСистемы");
	Иначе
		КомментарийДляЖурналаРегистрацииБезСтекаВызовов = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Недопустимое обращение к неинициализированным параметрам клиента на сервере.
			           |Вероятно, вызван выполнен после некорректной очистки параметров сеанса без использования %2.'",
			     ОбщегоНазначения.КодОсновногоЯзыка()),
			     "ОбщегоНазначения.ОчиститьПараметрыСеанса");
	КонецЕсли;
	
	Попытка
		ВызватьИсключение КомментарийДляЖурналаРегистрацииБезСтекаВызовов;
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
	КонецПопытки;
	КомментарийСоСтекомВызовов = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
	
	ИмяСобытия = НСтр("ru = 'Не заполнены параметры клиента на сервере'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	
	ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка,,, КомментарийСоСтекомВызовов);
	
	Если Не ПриЗапуске Тогда
		ТекстОшибки =
			НСтр("ru = 'Не инициализированы параметры клиента на сервере.
			           |Для их инициализации повторите действие или перезапустите сеанс.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат ПараметрыКлиента;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры для установки/обновления/получения параметров работы программы (кэшей).

// Проверяет, что в текущем сеансе доступна последняя версия программы,
// в противном случае, вызывает исключение с требованием перезапустить сеанс.
//
// В старых сеансах нельзя обновлять параметры работы программы, а также
// нельзя выполнять изменение некоторых данных, чтобы не перезаписать
// новую версию данных (полученную с помощью новой версии программы)
// старой версией данных (полученной с помощью старой версии программы).
//
Процедура ПроверитьДинамическоеОбновлениеВерсииПрограммы() Экспорт
	
	Если ВерсияПрограммыОбновленаДинамически() Тогда
		ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияВерсииПрограммы();
	КонецЕсли;
	
КонецПроцедуры

// Проверяет, что в текущем сеансе есть динамическое изменение конфигурации базы и
// при этом нет режима обновления информационной базы.
//
// Возвращаемое значение:
//  Булево - Истина, если версия программы обновлена.
//
Функция ВерсияПрограммыОбновленаДинамически() Экспорт
	
	Если Не КонфигурацияБазыДанныхИзмененаДинамически() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	// Если конфигурация базы данных изменена динамически после запуска
	// обновления информационной базы, но до его завершения, тогда нужно
	// продолжать обновление несмотря на изменение.
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		// Параметры работы программы только неразделенные, поэтому для них обновление завершено,
		// если завершено обновление неразделенных данных.
		Возврат Не ОбновлениеИнформационнойБазыСлужебный.НеобходимоОбновлениеНеразделенныхДанныхИнформационнойБазы();
	КонецЕсли;
	
	Возврат Не ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы();
	
КонецФункции

// Вызывает исключение с требованием перезапустить сеанс из-за обновления версии программы.
Процедура ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияВерсииПрограммы() Экспорт
	
	ТекстОшибки = НСтр("ru = 'Версия программы обновлена, требуется перезапустить сеанс.'");
	УстановитьТребуетсяПерезапускСеанса(ТекстОшибки);
	ВызватьИсключение ТекстОшибки;
	
КонецПроцедуры

// Вызывает исключение с требованием перезапустить сеанс из-за обновления расширений программы.
Процедура ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияРасширенийПрограммы() Экспорт
	
	Если ЭтоРазделенныйРежимСеансаБезРазделителей() Тогда
		ТекстОшибки =
			НСтр("ru = 'Для выполнения требуемых действий следует
			           |запустить сеанс с установленными разделителями.
			           |
			           |Расширения области данных не подключаются при входе
			           |в область данных в сеансе, запущенном без разделителей.'");
	Иначе
		ТекстОшибки = НСтр("ru = 'Расширения программы обновлены, требуется перезапустить сеанс.'");
	КонецЕсли;
	
	УстановитьТребуетсяПерезапускСеанса(ТекстОшибки);
	ВызватьИсключение ТекстОшибки;
	
КонецПроцедуры

// Возвращаемое значение:
//  Булево
//
Функция ЭтоРазделенныйРежимСеансаБезРазделителей() Экспорт
	
	Если Не ОбщегоНазначения.РазделениеВключено()
	 Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
	 Или Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	Возврат МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей();
	
КонецФункции

// Устанавливает параметр сеанса необходимости перезапуска с текстом
// краткого представления ошибки для проверки в исключении попытки.
//
// Параметры:
//  КраткоеПредставлениеОшибки - Строка - краткое представление текста ошибки при вызове
//   процедуры ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияВерсииПрограммы
//   или ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияРасширенийПрограммы.
//
Процедура УстановитьТребуетсяПерезапускСеанса(КраткоеПредставлениеОшибки) Экспорт
	
	Если ТекущийРежимЗапуска() <> Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();
	Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда
		Возврат;
	КонецЕсли;
	
	Если ТребуетсяПерезапускСеанса() Тогда
		Возврат;
	КонецЕсли;
	
	ТекущиеПараметры = Новый Структура(ПараметрыСеанса.УстановленныеРасширения);
	ТекущиеПараметры.Вставить("ТребуетсяПерезапускСеанса", КраткоеПредставлениеОшибки);
	ПараметрыСеанса.УстановленныеРасширения = Новый ФиксированнаяСтруктура(ТекущиеПараметры);
	
КонецПроцедуры

// Возвращает факт вызова процедуры УстановитьТребуетсяПерезапускСеанса и
// текст краткого представления ошибки установленный при вызове процедуры.
//
// Параметры:
//  КраткоеПредставлениеОшибки - Строка - возвращаемое значение,
//    установленное при вызове процедуры УстановитьТребуетсяПерезапускСеанса.
//
// Возвращаемое значение:
//  Булево
//
Функция ТребуетсяПерезапускСеанса(КраткоеПредставлениеОшибки = "") Экспорт
	
	Если Не ПараметрыСеанса.УстановленныеРасширения.Свойство("ТребуетсяПерезапускСеанса") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	КраткоеПредставлениеОшибки = ПараметрыСеанса.УстановленныеРасширения.ТребуетсяПерезапускСеанса;
	
	Возврат Истина;
	
КонецФункции

// Проверяет, что пойманное исключение - это ошибка, краткое представление которой
// начинается с текста, указанного при вызове процедуры УстановитьТребуетсяПерезапускСеанса.
//
// Параметры:
//  ИнформацияОбОшибке - ИнформацияОбОшибке
//
// Возвращаемое значение:
//  Булево
//
Функция ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Экспорт
	
	ТекстОшибки = "";
	Если Не ТребуетсяПерезапускСеанса(ТекстОшибки) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке")
	      И ЗначениеЗаполнено(ТекстОшибки)
	      И СтрНачинаетсяС(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке), ТекстОшибки);
	
КонецФункции

// Возвращает значение параметра работы программы.
//
// В старом сеансе (когда версия программы обновлена динамически),
// если параметр не существует, вызывается исключение с требованием перезапуска,
// иначе возвращается значение без учета версии.
//
// В разделенном режиме модели сервиса, если параметр не существует или
// версия параметра не равна версии конфигурации вызывается исключение,
// так как обновление неразделенных данных невозможно.
//
// Параметры:
//  ИмяПараметра - Строка - не более 128 символов. Например,
//                 "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//
// Возвращаемое значение:
//  Произвольный - возвращается Неопределено, когда параметр не существует или
//                 когда в новом сеансе версия параметра не равна версии конфигурации.
//
Функция ПараметрРаботыПрограммы(ИмяПараметра) Экспорт
	
	Возврат РегистрыСведений.ПараметрыРаботыПрограммы.ПараметрРаботыПрограммы(ИмяПараметра);
	
КонецФункции

// Устанавливает значение параметра работы программы.
// Перед вызовом требуется установить привилегированный режим.
//
// Параметры:
//  ИмяПараметра - Строка - не более 128 символов. Например,
//                 "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//
//  Значение     - Произвольный - значение, которое можно поместить в хранилище значения.
//
Процедура УстановитьПараметрРаботыПрограммы(ИмяПараметра, Значение) Экспорт
	
	РегистрыСведений.ПараметрыРаботыПрограммы.УстановитьПараметрРаботыПрограммы(ИмяПараметра, Значение);
	
КонецПроцедуры

// Обновляет значение параметра работы программы, если изменилось.
// Перед вызовом требуется установить привилегированный режим.
//
// Параметры:
//  ИмяПараметра   - Строка - не более 128 символов. Например,
//                   "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//
//  Значение       - Произвольный - значение, которое можно поместить в хранилище значения.
//
//  ЕстьИзменения  - Булево - возвращаемое значение. Устанавливается Истина,
//                   если старое и новое значения параметра не совпадают.
//
//  СтароеЗначение - Произвольный - возвращаемое значение. До обновления.
//
Процедура ОбновитьПараметрРаботыПрограммы(ИмяПараметра, Значение, ЕстьИзменения = Ложь, СтароеЗначение = Неопределено) Экспорт
	
	РегистрыСведений.ПараметрыРаботыПрограммы.ОбновитьПараметрРаботыПрограммы(ИмяПараметра,
		Значение, ЕстьИзменения, СтароеЗначение);
	
КонецПроцедуры

// Возвращает изменения параметра работы программы с учетом текущей версии
// конфигурации и текущей версии ИБ.
//
// Параметры:
//  ИмяПараметра - Строка - не более 128 символов. Например,
//                 "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//
// Возвращаемое значение:
//  Неопределено - означает, что изменилось все. Возвращается
//                 при начальном заполнении ИБ или области данных.
//  Массив       - содержит значения изменений, если массив пустой, значит изменений нет.
//                 Может быть несколько изменений, например, когда область данных давно не обновлялась.
//
Функция ИзмененияПараметраРаботыПрограммы(ИмяПараметра) Экспорт
	
	Возврат РегистрыСведений.ПараметрыРаботыПрограммы.ИзмененияПараметраРаботыПрограммы(ИмяПараметра);
	
КонецФункции

// Добавить изменения параметра работы программы при переходе на текущую версию метаданных конфигурации.
// В дальнейшем изменения используются для условного добавления обязательных обработчиков обновления.
// При начальном заполнении ИБ или неразделенных данных добавление изменений пропускается.
// 
// Параметры:
//  ИмяПараметра - Строка - не более 128 символов. Например,
//                 "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//
//  Изменения    - Произвольный - фиксированные данные, которые регистрируются в качестве изменений.
//                 Изменения не добавляются, если значение ИзменениеПараметра не заполнено.
//
Процедура ДобавитьИзмененияПараметраРаботыПрограммы(ИмяПараметра, Изменения) Экспорт
	
	РегистрыСведений.ПараметрыРаботыПрограммы.ДобавитьИзмененияПараметраРаботыПрограммы(ИмяПараметра, Изменения);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ЗарегистрироватьИзменениеПриоритетныхДанныхДляПодчиненныхУзловРИБ() Экспорт
	
	Если ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()
	 Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	Если Не СтандартныеПодсистемыПовтИсп.ОтключитьИдентификаторыОбъектовМетаданных() Тогда
		Справочники.ИдентификаторыОбъектовМетаданных.ЗарегистрироватьПолноеИзменениеДляПодчиненныхУзловРИБ();
	КонецЕсли;
	
	УзлыПлановОбменаРИБ = Новый Соответствие;
	Для Каждого ПланОбмена Из Метаданные.ПланыОбмена Цикл
		Если Не ПланОбмена.РаспределеннаяИнформационнаяБаза Тогда
			Продолжить;
		КонецЕсли;
		УзлыРИБ = Новый Массив;
		УзлыПлановОбменаРИБ.Вставить(ПланОбмена.Состав, УзлыРИБ);
		ПланОбменаМенеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПланОбмена.ПолноеИмя());
		Выборка = ПланОбменаМенеджер.Выбрать();
		Пока Выборка.Следующий() Цикл
			Если Выборка.Ссылка <> ПланОбменаМенеджер.ЭтотУзел() Тогда
				УзлыРИБ.Добавить(Выборка.Ссылка);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Если УзлыПлановОбменаРИБ.Количество() > 0 Тогда
		ЗарегистрироватьИзменениеПредопределенных(УзлыПлановОбменаРИБ, Метаданные.Справочники);
		ЗарегистрироватьИзменениеПредопределенных(УзлыПлановОбменаРИБ, Метаданные.ПланыВидовХарактеристик);
		ЗарегистрироватьИзменениеПредопределенных(УзлыПлановОбменаРИБ, Метаданные.ПланыСчетов);
		ЗарегистрироватьИзменениеПредопределенных(УзлыПлановОбменаРИБ, Метаданные.ПланыВидовРасчета);
	КонецЕсли;
	
КонецПроцедуры

// Создает во всех списках недостающие предопределенные элементы с новыми ссылками (уникальными идентификаторами).
// Для вызова после отключения подчиненного узла РИБ от главного, или для автоматического восстановления 
// отсутствующих предопределенных элементов.
//
Процедура ВосстановитьПредопределенныеЭлементы() Экспорт
	
	Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
		ВызватьИсключение 
			НСтр("ru = 'Восстановление предопределенных элементов следует выполнять только в главном узле РИБ.
			           |Затем выполнить синхронизацию с подчиненными узлами.'");
	КонецЕсли;
	
	ОбъектыМетаданных = ОбъектыМетаданныхВсехПредопределенныхДанных();
	Блокировка = Новый БлокировкаДанных;
	Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
		Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	КонецЦикла;
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		
		УстановитьИнициализациюВсехПредопределенныхДанных(ОбъектыМетаданных);
		СоздатьНедостающиеПредопределенныеДанные(ОбъектыМетаданных);
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Функция РеквизитыПредопределенныхДанных() Экспорт
	Результат = Новый Структура;
	Результат.Вставить("ИмяПредопределенныхДанных", "");
	Результат.Вставить("ИмяПредопределенногоНабора", "");
	Результат.Вставить("ИмяПредопределенногоВида", "");
	Результат.Вставить("ПредопределеннаяПапка", Ложь);
	Возврат Результат;
КонецФункции

Функция ЭтоПредопределенныеДанные(Знач Элемент, ИмяРеквизита = "", ЗначениеРеквизита = "") Экспорт // АПК:581 Экспортная для автотестов.
	
	// Для определения предопределенных элементов в подсистемах Свойства, КонтактнаяИнформация и Взаимодействия
	// зачитываются реквизиты ИмяПредопределенногоНабора, ИмяПредопределенногоВида и ПредопределеннаяПапка.
	ЗначенияРеквизитов = РеквизитыПредопределенныхДанных();
	ЗаполнитьЗначенияСвойств(ЗначенияРеквизитов, Элемент);
	Если ЗначенияРеквизитов.ИмяПредопределенныхДанных = ""
		И ЗначенияРеквизитов.ИмяПредопределенногоНабора = ""
		И ЗначенияРеквизитов.ИмяПредопределенногоВида = ""
		И Не ЗначенияРеквизитов.ПредопределеннаяПапка Тогда
		Возврат Ложь;
	КонецЕсли;

	ИмяРеквизита = "";
	Если ЗначенияРеквизитов.ИмяПредопределенногоНабора <> "" Тогда
		ИмяРеквизита = "ИмяПредопределенногоНабора";
	ИначеЕсли ЗначенияРеквизитов.ИмяПредопределенногоВида <> "" Тогда
		ИмяРеквизита = "ИмяПредопределенногоВида";
	ИначеЕсли ЗначенияРеквизитов.ПредопределеннаяПапка Тогда
		ИмяРеквизита = "ПредопределеннаяПапка";
	Иначе
		ИмяРеквизита = "ИмяПредопределенныхДанных";
	КонецЕсли;
	ЗначениеРеквизита = ЗначенияРеквизитов[ИмяРеквизита];
	
	Возврат Истина;
	
КонецФункции

// Параметры:
//  Ссылки - Массив из ЛюбаяСсылка
//         - ФиксированныйМассив из ЛюбаяСсылка - ссылки на объекты.
//           Если массив пуст, то результатом будет пустое соответствие.
//  Реквизиты - Массив из Строка
//            - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры.
//            - Строка - имена реквизитов через запятую
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение - список объектов и значений их реквизитов:
//   * Ключ - ЛюбаяСсылка - ссылка на объект;
//   * Значение - Структура:
//    ** Ключ - Строка - имя реквизита;
//    ** Значение - Произвольный - значение реквизита. Неопределено, если реквизит не существует у объекта.
// 
Функция ЗначенияРеквизитовОбъектовЕслиСуществуют(Ссылки, Знач Реквизиты) Экспорт
	
	ЗначенияРеквизитов = Новый Соответствие;
	Если Ссылки.Количество() = 0 Тогда
		Возврат ЗначенияРеквизитов;
	КонецЕсли;
	
	Если ТипЗнч(Реквизиты) = Тип("Строка") Тогда
		Реквизиты = СтрРазделить(Реквизиты, ",");
	КонецЕсли;
	
	РеквизитыТипов = Новый Соответствие;
	СсылкиПоТипам = Новый Соответствие;
	Для Каждого Ссылка Из Ссылки Цикл
		Тип = ТипЗнч(Ссылка);
		Если Не ОбщегоНазначения.ЭтоСсылка(Тип) Тогда
			Продолжить;
		КонецЕсли;
		
		Если СсылкиПоТипам[Тип] = Неопределено Тогда
			СсылкиПоТипам[Тип] = Новый Массив;
		КонецЕсли;
		ЭлементПоТипу = СсылкиПоТипам[Тип]; // Массив
		ЭлементПоТипу.Добавить(Ссылка);
		
		Если РеквизитыТипов[Тип] = Неопределено Тогда
			
			ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); // ОбъектМетаданныхСправочник
			Если ОбъектМетаданных = Неопределено Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Неверный первый параметр %1 в функции %2: 
						|Значения массива должны быть ссылками.'"), 
					"Ссылки", "ОбщегоНазначения.ЗначенияРеквизитовОбъектовЕслиСуществуют");
			КонецЕсли;
			РеквизитыТипа = Новый Массив;
			СтандартныеРеквизиты = Новый Соответствие;
			Для каждого СтандартныйРеквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
				СтандартныеРеквизиты[СтандартныйРеквизит.Имя] = Истина;	
			КонецЦикла;
			СтандартныеРеквизиты["ВерсияДанных"] = Истина;

			Для каждого ИмяРеквизита Из Реквизиты Цикл
				Если СтандартныеРеквизиты[ИмяРеквизита] <> Неопределено 
					Или ОбъектМетаданных.Реквизиты.Найти(ИмяРеквизита) <> Неопределено Тогда
					РеквизитыТипа.Добавить(ИмяРеквизита);
				Иначе
					РеквизитыТипа.Добавить("НЕОПРЕДЕЛЕНО КАК" + " " + ИмяРеквизита); // @query-part
				КонецЕсли;
			КонецЦикла;
			РеквизитыТипов[Тип] = РеквизитыТипа;
			
		КонецЕсли;
	КонецЦикла;
	
	
	Если СсылкиПоТипам.Количество() = 0 Тогда
		Возврат ЗначенияРеквизитов;
	КонецЕсли;
	
	ТекстыЗапросов = Новый Массив;
	Запрос = Новый Запрос;
	
	Для Каждого СсылкиПоТипу Из СсылкиПоТипам Цикл
		Тип = СсылкиПоТипу.Ключ;
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
		ПолноеИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя();

		ТекстЗапроса =
			"ВЫБРАТЬ РАЗРЕШЕННЫЕ
			|	Ссылка,
			|	&Реквизиты
			|ИЗ
			|	&ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы
			|ГДЕ
			|	ПсевдонимЗаданнойТаблицы.Ссылка В (&Ссылки)";
		Если ТекстыЗапросов.Количество() > 0 Тогда
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @query-part-1
		КонецЕсли;
		РеквизитыТекстЗапроса = СтрСоединить(РеквизитыТипов[Тип], ",");
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Реквизиты", РеквизитыТекстЗапроса);
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных);
		ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", "");
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра); // @query-part-1
		Запрос.УстановитьПараметр(ИмяПараметра, СсылкиПоТипу.Значение);

		ТекстыЗапросов.Добавить(ТекстЗапроса);
	КонецЦикла;
	
	ИменаРеквизитов = СтрСоединить(Реквизиты, ",");
	ТекстЗапроса = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); // @query-part
	Запрос.Текст = ТекстЗапроса;
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Результат = Новый Структура(ИменаРеквизитов);
		ЗаполнитьЗначенияСвойств(Результат, Выборка);
		ЗначенияРеквизитов[Выборка.Ссылка] = Результат;
	КонецЦикла;
	
	Возврат ЗначенияРеквизитов;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры для установки/получения параметров работы расширений (кэшей).

// Возвращает значения параметра для текущей версии расширений.
// Если не заполнен, возвращает Неопределено.
//
// Параметры:
//  ИмяПараметра - Строка - не более 128 символов. Например,
//                 "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//  
//  БезУчетаВерсииРасширений - Булево
//  
//  УжеИзменен - Булево - возвращаемое значение. Устанавливается Истина
//                 когда БезУчетаВерсииРасширений равно Истина,
//                 хранилище значения содержит значение отличное от Неопределено и
//                 значение было установлено более новым сеансом, чем текущий.
//             - Неопределено - установка значения не требуется.
//
// Возвращаемое значение:
//  Произвольный - возвращается Неопределено, если параметр не заполнен
//                 для текущей версии расширений.
//
Функция ПараметрРаботыРасширения(ИмяПараметра, БезУчетаВерсииРасширений = Ложь, УжеИзменен = Неопределено) Экспорт
	
	Возврат РегистрыСведений.ПараметрыРаботыВерсийРасширений.ПараметрРаботыРасширения(ИмяПараметра,
		БезУчетаВерсииРасширений, УжеИзменен);
	
КонецФункции

// Устанавливает хранилище значения параметра для текущей версии расширений.
// Используется для заполнения значений параметров.
// Перед вызовом требуется установить привилегированный режим.
//
// Параметры:
//  ИмяПараметра - Строка - не более 128 символов. Например,
//                 "СтандартныеПодсистемы.ВариантыОтчетов.ОтчетыСНастройками".
//
//  Значение     - Произвольный - значение параметра.
//  БезУчетаВерсииРасширений - Булево
//
Процедура УстановитьПараметрРаботыРасширения(ИмяПараметра, Значение, БезУчетаВерсииРасширений = Ложь) Экспорт
	
	РегистрыСведений.ПараметрыРаботыВерсийРасширений.УстановитьПараметрРаботыРасширения(ИмяПараметра, Значение, БезУчетаВерсииРасширений);
	
КонецПроцедуры

// Обработчик регламентного задания УдалениеУстаревшихПараметровРаботыВерсийРасширений.
Процедура УдалениеУстаревшихПараметровРаботыВерсийРасширенийОбработчикЗадания() Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(
		Метаданные.РегламентныеЗадания.УдалениеУстаревшихПараметровРаботыВерсийРасширений);
	
	УстановитьПривилегированныйРежим(Истина);
	Справочники.ВерсииРасширений.УдалитьУстаревшиеВерсииПараметров();
	
КонецПроцедуры

// Обработчик регламентного задания ЗаполнениеПараметровРаботыРасширений.
//
// Регламентное задание должно запускаться сразу, как только было включено.
// После успешного завершения задание отключает себя.
//
Процедура ЗаполнениеПараметровРаботыРасширений() Экспорт
	
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(
		Метаданные.РегламентныеЗадания.ЗаполнениеПараметровРаботыРасширений);
	
	УстановитьПривилегированныйРежим(Истина);
	РегистрыСведений.ПараметрыРаботыВерсийРасширений.ЗаполнитьВсеПараметрыРаботыПоследнейВерсииРасширений();
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ЗаполнитьВсеПараметрыРаботыРасширенийФоновоеЗадание(Параметры) Экспорт
	
	РегистрыСведений.ПараметрыРаботыВерсийРасширений.ЗаполнитьВсеПараметрыРаботыРасширенийФоновоеЗадание(Параметры);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Дополнительная базовая функциональность для обмена данными.

// Выполняет регистрацию изменений объекта на всех узлах плана обмена.
// Для разделенных конфигураций должны выполняться условия:
//  - план обмена должен быть разделенным,
//  - регистрируемый объект должен быть неразделенным.
//
//  Параметры:
//    Объект         - СправочникОбъект
//                   - ДокументОбъект
//                   - БизнесПроцессОбъект
//                   - ЗадачаОбъект
//                   - ПланВидовРасчетаОбъект
//                   - ПланВидовХарактеристикОбъект
//                   - ПланСчетовОбъект
//                   - ПланОбменаОбъект
//
//    ИмяПланаОбмена - Строка - имя плана обмена, на всех узлах которого требуется выполнить регистрацию объекта.
//                              План обмена должен быть разделенным, иначе будет выдано исключение.
//
//    ВключаяГлавныйУзел - Булево - если Ложь, тогда в подчиненном узле
//                         не будет выполнена регистрация для главного узла.
// 
//
Процедура ЗарегистрироватьОбъектНаВсехУзлах(Знач Объект, Знач ИмяПланаОбмена, Знач ВключаяГлавныйУзел = Истина) Экспорт
	
	Если Метаданные.ПланыОбмена[ИмяПланаОбмена].Состав.Найти(Объект.Метаданные()) = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		
		Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
			ВызватьИсключение НСтр("ru = 'Регистрация изменений неразделенных данных в разделенном режиме.'");
		КонецЕсли;
		
		МодульРаботаВМоделиСервиса = Неопределено;
		Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
			МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		КонецЕсли;
		
		Если МодульРаботаВМоделиСервиса <> Неопределено Тогда
			ЭтоРазделенныйПланОбмена = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(
				"ПланОбмена." + ИмяПланаОбмена, МодульРаботаВМоделиСервиса.РазделительОсновныхДанных());
		Иначе
			ЭтоРазделенныйПланОбмена = Ложь;
		КонецЕсли;
		
		Если Не ЭтоРазделенныйПланОбмена Тогда
			ВызватьИсключение НСтр("ru = 'Регистрация изменений для неразделенных планов обмена не поддерживается.'");
		КонецЕсли;
		
		Если МодульРаботаВМоделиСервиса <> Неопределено Тогда
			ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(
				Объект.Метаданные().ПолноеИмя(), МодульРаботаВМоделиСервиса.РазделительОсновныхДанных());
		Иначе
			ЭтоРазделенныйОбъектМетаданных = Ложь;
		КонецЕсли;
		
		Если ЭтоРазделенныйОбъектМетаданных Тогда
				ВызватьИсключение НСтр("ru = 'Регистрация изменений для разделенных объектов не поддерживается.'");
		КонецЕсли;
		
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	ПланОбмена.Ссылка КАК Получатель
		|ИЗ
		|	#ТаблицаПланаОбмена КАК ПланОбмена
		|ГДЕ
		|	ПланОбмена.РегистрироватьИзменения
		|	И НЕ ПланОбмена.ЭтотУзел
		|	И НЕ ПланОбмена.ПометкаУдаления";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТаблицаПланаОбмена", "ПланОбмена." + ИмяПланаОбмена);
		
		Запрос = Новый Запрос;
		Запрос.Текст = ТекстЗапроса;
		
		Получатели = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Получатель");
		
		Для Каждого Получатель Из Получатели Цикл
			
			Объект.ОбменДанными.Получатели.Добавить(Получатель);
			
		КонецЦикла;
		
	Иначе
		
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	ПланОбмена.Ссылка КАК Получатель
		|ИЗ
		|	#ТаблицаПланаОбмена КАК ПланОбмена
		|ГДЕ
		|	НЕ ПланОбмена.ЭтотУзел
		|	И НЕ ПланОбмена.ПометкаУдаления";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТаблицаПланаОбмена", "ПланОбмена." + ИмяПланаОбмена);
		
		Запрос = Новый Запрос;
		Запрос.Текст = ТекстЗапроса;
		
		Получатели = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Получатель");
		
		ГлавныйУзел = ПланыОбмена.ГлавныйУзел();
		
		Для Каждого Получатель Из Получатели Цикл
			Если Не ВключаяГлавныйУзел И Получатель = ГлавныйУзел Тогда
				Продолжить;
			КонецЕсли;
			Объект.ОбменДанными.Получатели.Добавить(Получатель);
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

// Сохраняет ссылку на главный узел в константе ГлавныйУзел для возможности восстановления.
Процедура СохранитьГлавныйУзел() Экспорт
	
	ГлавныйУзелМенеджер = Константы.ГлавныйУзел.СоздатьМенеджерЗначения();
	ГлавныйУзелМенеджер.Значение = ПланыОбмена.ГлавныйУзел();
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(ГлавныйУзелМенеджер);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики отправки и получения данных для обмена в распределенной ИБ.

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание параметров в обработчике события ПриОтправкеДанныхПодчиненному в синтакс-помощнике.
// 
// Параметры:
//  ЭлементДанных - Произвольный
//  ОтправкаЭлемента - ОтправкаЭлементаДанных
//  СозданиеНачальногоОбраза - Булево
//  Получатель - ПланОбменаОбъект
// 
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, Знач СозданиеНачальногоОбраза, Знач Получатель) Экспорт
	
	Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Отправка идентификаторов объектов метаданных выполняется в другой секции сообщения обмена.
	ИгнорироватьОтправкуИдентификаторовОбъектовМетаданных(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза);
	ИгнорироватьОтправкуДанныхОбработанныхВЦентральномУзлеРИБПриОбновленииИБ(ЭлементДанных, СозданиеНачальногоОбраза, Получатель);
	Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	ПодсистемаОбменДаннымиСуществует = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными");
	
	// Вставка кода от подсистемы обмена данными должна быть первой.
	Если ПодсистемаОбменДаннымиСуществует Тогда
		МодульОбменДаннымиСобытия = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСобытия");
		МодульОбменДаннымиСобытия.ПриОтправкеДанныхКорреспонденту(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель, Ложь);
		
		Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель);
	Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Вставка кода от подсистемы обмена данными в модели сервиса должна быть последней, влияющей на логику отправки.
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		МодульОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиВМоделиСервиса");
		МодульОбменДаннымиВМоделиСервиса.ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель);
		
		Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Если ПодсистемаОбменДаннымиСуществует Тогда
		МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
		МодульОбменДаннымиСервер.РассчитатьПроцентВыгрузкиРИБ(Получатель, СозданиеНачальногоОбраза);
	КонецЕсли;
	
КонецПроцедуры

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание параметров в обработчике события ПриПолученииДанныхОтПодчиненного в синтакс-помощнике.
// 
// Параметры:
//  ЭлементДанных - Произвольный
//  ПолучениеЭлемента - ПолучениеЭлементаДанных
//  ОтправкаНазад - Булево
//  Отправитель - ПланОбменаОбъект
// 
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Знач Отправитель) Экспорт
	
	// Идентификаторы объектов метаданных могут изменяться только в главном узле.
	ИгнорироватьПолучениеИдентификаторовОбъектовМетаданных(ЭлементДанных, ПолучениеЭлемента);
	
	Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель);
	Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
	ОбщегоНазначенияПереопределяемый.ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель);
	
	ПодсистемаОбменДаннымиСуществует = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными");
	
	// Вставка кода от подсистемы обмена данными должна быть последней, влияющей на логику получения.
	Если ПодсистемаОбменДаннымиСуществует Тогда
		МодульОбменДаннымиСобытия = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСобытия");
		МодульОбменДаннымиСобытия.ПриПолученииДанныхОтПодчиненногоВКонце(ЭлементДанных, ПолучениеЭлемента, Отправитель);
	КонецЕсли;
	
	Если ПодсистемаОбменДаннымиСуществует Тогда
		МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
		МодульОбменДаннымиСервер.РассчитатьПроцентЗагрузкиРИБ(Отправитель);
	КонецЕсли;
	
КонецПроцедуры

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание обработчика события ПриПолученииДанныхОтГлавного в синтакс-помощнике.
// Параметр Отправитель может быть не заполнен, например, при получении сообщения начального образа в АРМе.
// 
// Параметры:
//  ЭлементДанных - Произвольный
//  ПолучениеЭлемента - ПолучениеЭлементаДанных
//  ОтправкаНазад - Булево
//  Отправитель - ПланОбменаОбъект
//
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель = Неопределено) Экспорт
	
	Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	ПодсистемаОбменДаннымиСуществует = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными");
	
	// Вставка кода от подсистемы обмена данными должна быть первой.
	Если ПодсистемаОбменДаннымиСуществует Тогда
		МодульОбменДаннымиСобытия = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСобытия");
		МодульОбменДаннымиСобытия.ПриПолученииДанныхОтГлавногоВНачале(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель);
		
		Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель);
	Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
	ОбщегоНазначенияПереопределяемый.ПриПолученииДанныхОтГлавного(Отправитель, ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад);
	
	// Вставка кода от подсистемы обмена данными должна быть последней, влияющей на логику получения.
	Если ПодсистемаОбменДаннымиСуществует
		И Не СозданиеНачальногоОбраза(ЭлементДанных) Тогда
		
		МодульОбменДаннымиСобытия = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСобытия");
		МодульОбменДаннымиСобытия.ПриПолученииДанныхОтГлавногоВКонце(ЭлементДанных, ПолучениеЭлемента, Отправитель);
		
	КонецЕсли;
	
	Если ПодсистемаОбменДаннымиСуществует Тогда
		МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
		МодульОбменДаннымиСервер.РассчитатьПроцентЗагрузкиРИБ(Отправитель);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Дополнительные функции для работы с типами.

// Возвращает тип ссылки или ключа записи указанного объекта метаданных.
//
// Параметры:
//  ОбъектМетаданных - ОбъектМетаданных - регистр или ссылочный объект.
//
//  Возвращаемое значение:
//   Тип
//
Функция ТипСсылкиИлиКлючаЗаписиОбъектаМетаданных(ОбъектМетаданных) Экспорт
	
	Если ОбщегоНазначения.ЭтоРегистр(ОбъектМетаданных) Тогда
		
		Если ОбщегоНазначения.ЭтоРегистрСведений(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрСведений";
			
		ИначеЕсли ОбщегоНазначения.ЭтоРегистрНакопления(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрНакопления";
			
		ИначеЕсли ОбщегоНазначения.ЭтоРегистрБухгалтерии(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрБухгалтерии";
			
		ИначеЕсли ОбщегоНазначения.ЭтоРегистрРасчета(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрРасчета";
		КонецЕсли;
		Тип = Тип(ВидРегистра + "КлючЗаписи." + ОбъектМетаданных.Имя);
	Иначе
		Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
		Тип = ТипЗнч(Менеджер.ПустаяСсылка());
	КонецЕсли;
	
	Возврат Тип;
	
КонецФункции

// Возвращает тип объекта или набора записей указанного объекта метаданных.
//
// Параметры:
//  ОбъектМетаданных - ОбъектМетаданных - регистр или ссылочный объект.
//
//  Возвращаемое значение:
//   Тип
//
Функция ТипОбъектаИлиНабораЗаписейОбъектаМетаданных(ОбъектМетаданных) Экспорт
	
	Если ОбщегоНазначения.ЭтоРегистр(ОбъектМетаданных) Тогда
		
		Если ОбщегоНазначения.ЭтоРегистрСведений(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрСведений";
			
		ИначеЕсли ОбщегоНазначения.ЭтоРегистрНакопления(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрНакопления";
			
		ИначеЕсли ОбщегоНазначения.ЭтоРегистрБухгалтерии(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрБухгалтерии";
			
		ИначеЕсли ОбщегоНазначения.ЭтоРегистрРасчета(ОбъектМетаданных) Тогда
			ВидРегистра = "РегистрРасчета";
		КонецЕсли;
		Тип = Тип(ВидРегистра + "НаборЗаписей." + ОбъектМетаданных.Имя);
	Иначе
		Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
		ВидОбъекта = ОбщегоНазначения.ВидОбъектаПоТипу(ТипЗнч(Менеджер.ПустаяСсылка()));
		Тип = Тип(ВидОбъекта + "Объект." + ОбъектМетаданных.Имя);
	КонецЕсли;
	
	Возврат Тип;
	
КонецФункции

// Выполняет проверку, что переданный объект имеет тип СправочникОбъект.ИдентификаторыОбъектовМетаданных.
//
// Параметры:
//  Объект - Произвольный
// 
// Возвращаемое значение:
//  Булево
//
Функция ЭтоИдентификаторОбъектаМетаданных(Объект) Экспорт
	
	Возврат ТипЗнч(Объект) = Тип("СправочникОбъект.ИдентификаторыОбъектовМетаданных");
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции работы с формами.

// Устанавливает ключ назначения формы (ключ назначения использования и
// ключ сохранения положения окна). При необходимости копирует текущие настройки формы,
// если для соответствующего нового ключа они еще не были записаны.
//
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - форма ПриСозданииНаСервере, которой устанавливается ключ.
//  Ключ  - Строка - новый ключ назначения формы.
//  КлючПоложения - Строка
//  УстановитьНастройки - Булево - установить новому ключу настройки, сохраненные для текущего ключа.
//
Процедура УстановитьКлючНазначенияФормы(Форма, Ключ, КлючПоложения = "", УстановитьНастройки = Истина) Экспорт
	
	УстановитьКлючНазначенияИспользованияФормы(Форма, Ключ, УстановитьНастройки);
	УстановитьКлючСохраненияПоложенияОкнаФормы(Форма, ?(КлючПоложения = "", Ключ, КлючПоложения), УстановитьНастройки);
	
КонецПроцедуры

Процедура СброситьРазмерыИПоложениеОкна(Форма) Экспорт
	
	Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
		Возврат;
	КонецЕсли;
	
	ИмяФормы = Форма.ИмяФормы;
	НовыйКлючСохраненияПоложенияОкна = СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "_");
	КлючОбъектаХранения = ИмяФормы + "/ВременныеКлючиСохраненияПоложенияОкна";
	ИмяПользователя = ИмяПользователя();
	НачалоДня = НачалоДня(ТекущаяУниверсальнаяДата());
	ГраницаУстаревания = НачалоДня - 2*24*60*60;
	
	Ключи = ХранилищеСистемныхНастроек.Загрузить(КлючОбъектаХранения);
	
	Если ТипЗнч(Ключи) = Тип("Соответствие") Тогда
		ИменаНастроек = Новый Массив;
		ИменаНастроек.Добавить("/НастройкиОкнаТонкогоКлиента");
		ИменаНастроек.Добавить("/Такси/НастройкиОкнаТонкогоКлиента");
		ИменаНастроек.Добавить("/НастройкиОкнаВебКлиента");
		ИменаНастроек.Добавить("/НастройкиОкнаМобильногоКлиента");
		ИменаНастроек.Добавить("/Такси/НастройкиОкнаВебКлиента");
		ИменаНастроек.Добавить("/Такси/НастройкиОкнаМобильногоКлиента");
		ТекущиеКлючи = Новый Соответствие(Новый ФиксированноеСоответствие(Ключи));
		Для Каждого КлючИЗначение Из ТекущиеКлючи Цикл
			ТекущийДень = КлючИЗначение.Ключ;
			Если ТипЗнч(ТекущийДень) <> Тип("Дата") Тогда
				Ключи = Неопределено;
				Прервать;
			КонецЕсли;
			Если ТекущийДень > ГраницаУстаревания Тогда
				Продолжить;
			КонецЕсли;
			КлючиТекущегоДня = КлючИЗначение.Значение;
			Если ТипЗнч(КлючиТекущегоДня) <> Тип("Массив") Тогда
				Ключи = Неопределено;
				Прервать;
			КонецЕсли;
			Для Каждого ТекущийКлюч Из КлючиТекущегоДня Цикл
				НачалоКлючаОбъекта = ИмяФормы + "/" + ТекущийКлюч;
				Для Каждого ИмяНастройки Из ИменаНастроек Цикл
					ХранилищеСистемныхНастроек.Удалить(НачалоКлючаОбъекта + ИмяНастройки, "", ИмяПользователя);
				КонецЦикла;
			КонецЦикла;
			Ключи.Удалить(ТекущийДень);
		КонецЦикла;
	КонецЕсли;
	
	ОчиститьСтарыеКлючи = ТипЗнч(Ключи) <> Тип("Соответствие");
	Если ОчиститьСтарыеКлючи Тогда
		Ключи = Новый Соответствие;
	КонецЕсли;
	
	КлючиДня = Ключи.Получить(НачалоДня);
	Если ТипЗнч(КлючиДня) <> Тип("Массив") Тогда
		КлючиДня = Новый Массив;
		Ключи.Вставить(НачалоДня, КлючиДня);
	КонецЕсли;
	КлючиДня.Добавить(НовыйКлючСохраненияПоложенияОкна);
	ХранилищеСистемныхНастроек.Сохранить(КлючОбъектаХранения,, Ключи);
	
	Форма.КлючСохраненияПоложенияОкна = НовыйКлючСохраненияПоложенияОкна;
	
	Если Не ОчиститьСтарыеКлючи Тогда
		Возврат;
	КонецЕсли;
	
	Отбор = Новый Структура("Пользователь", ИмяПользователя);
	Выборка = ХранилищеСистемныхНастроек.Выбрать(Отбор);
	КлючПоискаРусский = "НастройкиОкнаТонкогоКлиента"; // @Non-NLS
	КлючПоискаАнглийский = "ThinClientWindowSettings";
	Пока Истина Цикл
		Попытка
			ЕстьСледующей = Выборка.Следующий();
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ЗаписьЖурналаРегистрации(
				НСтр("ru = 'Ошибка выполнения'", ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,,,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
			Прервать;
		КонецПопытки;
		Если Не ЕстьСледующей Тогда
			Прервать;
		КонецЕсли;
		Если Не СтрНачинаетсяС(Выборка.КлючОбъекта, ИмяФормы)
		 Или Выборка.КлючНастроек <> ""
		 Или Выборка.КлючОбъекта = КлючОбъектаХранения Тогда
			Продолжить;
		КонецЕсли;
		ЧастиКлючаОбъекта = СтрРазделить(Выборка.КлючОбъекта, "/");
		Если ЧастиКлючаОбъекта.Количество() < 2 Тогда
			Продолжить;
		КонецЕсли;
		ПоследняяЧастьКлюча = ЧастиКлючаОбъекта[ЧастиКлючаОбъекта.ВГраница()];
		Если СтрНайти(ПоследняяЧастьКлюча, КлючПоискаРусский) > 0
		 Или СтрНайти(ПоследняяЧастьКлюча, КлючПоискаАнглийский) > 0 Тогда
			ХранилищеСистемныхНастроек.Удалить(Выборка.КлючОбъекта, "", ИмяПользователя);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Прочие процедуры и функции.

// Возвращает уточнения при возникновении проблем с параметрами работы программы.
// 
// Возвращаемое значение:
//  Строка
//
Функция УточнениеОшибкиПараметровРаботыПрограммыДляРазработчика() Экспорт
	
	Возврат Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( 
		НСтр("ru = 'Для разработчика: возможно требуется обновить вспомогательные данные,
			|которые влияют на работу программы. Для выполнения обновления можно:
			|- воспользоваться внешней обработкой
			|  ""Инструменты разработчика: Обновление вспомогательных данных"",
			|- либо запустить программу с параметром командной строки 1С:Предприятия 8
			|  ""/С %1"",
			|- либо увеличить номер версии конфигурации, чтобы при очередном запуске
			|  выполнились процедуры обновления данных информационной базы.'"),
		"ЗапуститьОбновлениеИнформационнойБазы");
	
КонецФункции

// Возвращает текущего пользователя информационной базы.
// 
// Возвращаемое значение:
//  ПользовательИнформационнойБазы
//
Функция ТекущийПользователь() Экспорт
	
	// Вычисляем актуальное имя пользователя, даже если оно было ранее изменено в текущем сеансе;
	// Например, для подключения к текущей ИБ через внешнее соединение из этого сеанса;
	// Во всех остальных случаях достаточно получить ПользователиИнформационнойБазы.ТекущийПользователь().
	ТекущийПользователь = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(
		ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор);
	
	Если ТекущийПользователь = Неопределено Тогда
		ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
	КонецЕсли;
	
	Возврат ТекущийПользователь;
	
КонецФункции

// Преобразует строку в допустимое наименование колонки таблицы значений, заменяя недопустимые
// символы на код символа ограниченного символом подчеркивания.
//
// Параметры:
//  Строка - Строка - строка для преобразования.
// 
// Возвращаемое значение:
//  Строка - строка, содержащая только допустимые символы для наименования колонок таблицы значений.
//
Функция ПреобразоватьСтрокуВДопустимоеНаименованиеКолонки(Строка) Экспорт
	
	НедопустимыеСимволы = ":;!@#$%^&-~`'.,?{}[]+=*/|\ ()_""";
	Результат = "";
	Для Индекс = 1 По СтрДлина(Строка) Цикл
		Символ =  Сред(Строка, Индекс, 1);
		Если СтрНайти(НедопустимыеСимволы, Символ) > 0 Или (КодСимвола(Символ) > 126 И КодСимвола(Символ) < 256) Тогда
			Результат = Результат + "_" + КодСимвола(Символ) + "_";
		Иначе
			Результат = Результат + Символ;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Преобразовать адаптированное наименование колонки, в котором недопустимые
// символы заменены на код символа, ограниченного символом подчеркивания в обычную строку.
//
// Параметры:
//  НаименованиеКолонки - Строка - адаптированное наименование колонки.
// 
// Возвращаемое значение:
//  Строка - преобразованная строка.
//
Функция ПреобразоватьАдаптированноеНаименованиеКолонкиВСтроку(НаименованиеКолонки) Экспорт
	
	Результат = "";
	Для Индекс = 1 По СтрДлина(НаименованиеКолонки) Цикл
		Символ = Сред(НаименованиеКолонки, Индекс, 1);
		Если Символ = "_" Тогда
			ПозицияЗакрывающегоСимвола = СтрНайти(НаименованиеКолонки, "_", НаправлениеПоиска.СНачала, Индекс + 1);
			КодСимвола = Сред(НаименованиеКолонки, Индекс + 1, ПозицияЗакрывающегоСимвола - Индекс - 1);
			Результат = Результат + Символ(КодСимвола);
			Индекс = ПозицияЗакрывающегоСимвола;
		Иначе
			Результат = Результат + Символ;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Формирует сведения, необходимые для оповещения на клиенте открытых форм и динамических списков
// о массовых изменениях объектов, которые произошли на сервере.
//
// Параметры:
//   ИзмененныеОбъекты - ЛюбаяСсылка
//                     - Тип
//                     - Массив - содержит сведения об измененных объектах.
//                       Может быть передана ссылка или массив ссылок на измененные объекты,
//                       либо можно указать тип или массив типов измененных объектов.
//
// Возвращаемое значение:
//   Соответствие из КлючИЗначение:
//     * Ключ - Тип - например, ДокументСсылка.ЗаказПокупателя.
//     * Значение - Структура:
//        ** ИмяСобытия - Строка - например, "Запись_ЗаказПокупателя".
//        ** ПустаяСсылка - ЛюбаяСсылка
// 
Функция ПодготовитьОповещениеФормОбИзменении(ИзмененныеОбъекты) Экспорт
	
	Результат = Новый Соответствие;
	Если ИзмененныеОбъекты = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	МассивТипов = Новый Массив;
	ТипСсылкиИлиТипаИлиМассива = ТипЗнч(ИзмененныеОбъекты);
	Если ТипСсылкиИлиТипаИлиМассива = Тип("Массив") Тогда
		Для Каждого Элемент Из ИзмененныеОбъекты Цикл
			ТипЭлемента = ТипЗнч(Элемент);
			Если ТипЭлемента = Тип("Тип") Тогда
				ТипЭлемента = Элемент;
			КонецЕсли;
			Если МассивТипов.Найти(ТипЭлемента) = Неопределено Тогда
				МассивТипов.Добавить(ТипЭлемента);
			КонецЕсли;
		КонецЦикла;
	Иначе
		МассивТипов.Добавить(ИзмененныеОбъекты);
	КонецЕсли;
	
	Для Каждого ТипЭлемента Из МассивТипов Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЭлемента);
		Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда
			Продолжить;
		КонецЕсли;
		ИмяСобытия = "Запись_" + ОбъектМетаданных.Имя;
		Попытка
			ПустаяСсылка = ПредопределенноеЗначение(ОбъектМетаданных.ПолноеИмя() + ".ПустаяСсылка");
		Исключение
			ПустаяСсылка = Неопределено;
		КонецПопытки;
		Результат.Вставить(ТипЭлемента, Новый Структура("ИмяСобытия,ПустаяСсылка", ИмяСобытия, ПустаяСсылка));
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

// Устанавливает общую форму ПустойРабочийСтол на рабочий стол с пустым составом форм.
//
// Для корректного отображения разделенного рабочего стола в веб-клиенте
// неразделенный рабочий стол должен иметь не пустой состав форм, и наоборот.
//
Процедура УстановитьПустуюФормуНаПустойРабочийСтол() Экспорт
	
	КлючОбъекта = "Общее/НастройкиНачальнойСтраницы";
	
	ТекущиеНастройки = ХранилищеСистемныхНастроек.Загрузить(КлючОбъекта);
	Если ТекущиеНастройки = Неопределено Тогда
		ТекущиеНастройки = Новый НастройкиНачальнойСтраницы;
	КонецЕсли;
	
	ТекущийСоставФорм = ТекущиеНастройки.ПолучитьСоставФорм();
	
	Если ТекущийСоставФорм.ЛеваяКолонка.Количество() = 0
	   И ТекущийСоставФорм.ПраваяКолонка.Количество() = 0 Тогда
		
		ТекущийСоставФорм.ЛеваяКолонка.Добавить("ОбщаяФорма.ПустойРабочийСтол");
		ТекущиеНастройки.УстановитьСоставФорм(ТекущийСоставФорм);
		ХранилищеСистемныхНастроек.Сохранить(КлючОбъекта, "", ТекущиеНастройки);
	КонецЕсли;
	
КонецПроцедуры

// Проверяет доступность проведения списка документов текущему пользователю.
//
// Параметры:
//  СписокДокументов - Массив - документы для проверки.
//
// Возвращаемое значение:
//  Булево - Истина, если есть право проведения хотя бы для одного документа.
//
Функция ДоступноПравоПроведения(СписокДокументов) Экспорт
	ТипыДокументов = Новый Массив;
	Для Каждого Документ Из СписокДокументов Цикл
		ТипДокумента = ТипЗнч(Документ);
		Если ТипыДокументов.Найти(ТипДокумента) <> Неопределено Тогда
			Продолжить;
		Иначе
			ТипыДокументов.Добавить(ТипДокумента);
		КонецЕсли;
		Если ПравоДоступа("Проведение", Метаданные.НайтиПоТипу(ТипДокумента)) Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	Возврат Ложь;
КонецФункции

// Проверяет, что переданная таблица является регистром.
// 
// Параметры:
//  ИмяТаблицы - Строка - полное имя таблицы.
// 
// Возвращаемое значение:
//  Булево 
//
Функция ЭтоТаблицаРегистра(ИмяТаблицы) Экспорт
	ВРегИмяТаблицы = ВРег(ИмяТаблицы);
	Если СтрНачинаетсяС(ВРегИмяТаблицы, ВРег("РегистрСведений"))
		Или СтрНачинаетсяС(ВРегИмяТаблицы, ВРег("РегистрНакопления"))
		Или СтрНачинаетсяС(ВРегИмяТаблицы, ВРег("РегистрБухгалтерии"))
		Или СтрНачинаетсяС(ВРегИмяТаблицы, ВРег("РегистрРасчета")) Тогда
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
КонецФункции

// Возвращает представление начальной (главной) страницы.
//
// Возвращаемое значение:
//   Строка
//
Функция ПредставлениеНачальнойСтраницы() Экспорт 
	
	Возврат НСтр("ru = 'Главное'");
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ЗагрузкаДанныхИзФайлаПереопределяемый.ПриОпределенииСправочниковДляЗагрузкиДанных.
Процедура ПриОпределенииСправочниковДляЗагрузкиДанных(ЗагружаемыеСправочники) Экспорт
	
	// Загрузка в справочник ИдентификаторыОбъектовМетаданных запрещена.
	СтрокаТаблицы = ЗагружаемыеСправочники.Найти(Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.ПолноеИмя(), "ПолноеИмя");
	Если СтрокаТаблицы <> Неопределено Тогда 
		ЗагружаемыеСправочники.Удалить(СтрокаТаблицы);
	КонецЕсли;
	
	// Загрузка в справочник ИдентификаторыОбъектовРасширений запрещена.
	СтрокаТаблицы = ЗагружаемыеСправочники.Найти(Метаданные.Справочники.ИдентификаторыОбъектовРасширений.ПолноеИмя(), "ПолноеИмя");
	Если СтрокаТаблицы <> Неопределено Тогда 
		ЗагружаемыеСправочники.Удалить(СтрокаТаблицы);
	КонецЕсли;
	
КонецПроцедуры

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт
	
	Объекты.Вставить(Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.ПолноеИмя(), "РеквизитыРедактируемыеВГрупповойОбработке");
	Объекты.Вставить(Метаданные.Справочники.ИдентификаторыОбъектовРасширений.ПолноеИмя(), "РеквизитыРедактируемыеВГрупповойОбработке");
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.
Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт
	
	ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.БезопасноеХранилищеДанных.Измерения.Владелец);
	ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.Измерения.Владелец);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиента.
Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт
	
	ДобавитьПараметрыРаботыКлиента(Параметры);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииСерверныхОповещений
Процедура ПриДобавленииСерверныхОповещений(Оповещения) Экспорт
	
	// ФункциональныеОпцииИзменены
	Оповещение = СерверныеОповещения.НовоеСерверноеОповещение(
		"СтандартныеПодсистемы.БазоваяФункциональность.ФункциональныеОпцииИзменены");
	
	Оповещение.ИмяМодуляОтправки  = "СтандартныеПодсистемыСервер";
	Оповещение.ИмяМодуляПолучения = "СтандартныеПодсистемыКлиент";
	
	Оповещения.Вставить(Оповещение.Имя, Оповещение);
	
	// ПовторноИспользуемыеЗначенияУстарели
	Оповещение = СерверныеОповещения.НовоеСерверноеОповещение(
		"СтандартныеПодсистемы.БазоваяФункциональность.ПовторноИспользуемыеЗначенияУстарели");
	
	Оповещение.ИмяМодуляПолучения = "СтандартныеПодсистемыКлиент";
	
	Оповещения.Вставить(Оповещение.Имя, Оповещение);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗаполненииТиповОбщихДанныхПоддерживающихСопоставлениеСсылокПриЗагрузке.
Процедура ПриЗаполненииТиповОбщихДанныхПоддерживающихСопоставлениеСсылокПриЗагрузке(Типы) Экспорт
	
	Типы.Добавить(Метаданные.Справочники.ИдентификаторыОбъектовМетаданных);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриЗаполненииТиповИсключаемыхИзВыгрузкиЗагрузки.
Процедура ПриЗаполненииТиповИсключаемыхИзВыгрузкиЗагрузки(Типы) Экспорт
	
	Типы.Добавить(Метаданные.Константы.АдресПубликацииИнформационнойБазыВИнтернете);
	Типы.Добавить(Метаданные.Константы.АдресПубликацииИнформационнойБазыВЛокальнойСети);
	Типы.Добавить(Метаданные.Константы.ИдентификаторИнформационнойБазы);
	Типы.Добавить(Метаданные.Константы.ДоставлятьСерверныеОповещенияБезСистемыВзаимодействия);
	Типы.Добавить(Метаданные.Константы.РегистрироватьПоказателиСерверныхОповещений);
	МодульВыгрузкаЗагрузкаДанных = ОбщегоНазначения.ОбщийМодуль("ВыгрузкаЗагрузкаДанных");
	МодульВыгрузкаЗагрузкаДанных.ДополнитьТипомИсключаемымИзВыгрузкиЗагрузки(Типы,
		Метаданные.Справочники.ВерсииРасширений,
		МодульВыгрузкаЗагрузкаДанных.ДействиеСоСсылкамиНеИзменять());
	МодульВыгрузкаЗагрузкаДанных.ДополнитьТипомИсключаемымИзВыгрузкиЗагрузки(Типы,
		Метаданные.Справочники.ИдентификаторыОбъектовРасширений,
		МодульВыгрузкаЗагрузкаДанных.ДействиеСоСсылкамиНеИзменять());
	Типы.Добавить(Метаданные.РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных);
	Типы.Добавить(Метаданные.РегистрыСведений.ИдентификаторыОбъектовВерсийРасширений);
	Типы.Добавить(Метаданные.РегистрыСведений.ПараметрыРаботыВерсийРасширений);
	
КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам.
Процедура ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений) Экспорт
	
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	
	Разрешения = Новый Массив();
	
	Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеКаталогаВременныхФайлов(Истина, Истина,
		НСтр("ru = 'Для возможности работы программы.'")));
	Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеПривилегированногоРежима());
	
	ЗапросыРазрешений.Добавить(
		МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения));
	
	ДобавитьЗапросРазрешенийНаИспользованиеРасширений(ЗапросыРазрешений);
	
КонецПроцедуры

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
	
	Идентификатор = "КонтрольДинамическогоОбновленияПрограммы";
	Дело = ТекущиеДела.Добавить();
	Дело.Идентификатор = Идентификатор;
	Дело.ЕстьДела      = КонфигурацияБазыДанныхИзмененаДинамически()
	                     Или Справочники.ВерсииРасширений.РасширенияИзмененыДинамически();
	Дело.Важное        = Ложь;
	Дело.Представление = НСтр("ru = 'Установлено обновление приложения'");
	Дело.Форма         = "ОбщаяФорма.КонтрольДинамическогоОбновления";
	Дело.Владелец      = НСтр("ru = 'Работа приложения'");
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если МодульТекущиеДелаСервер.ДелоОтключено("РекомендацияПоПовышениюСкоростиРаботы") Тогда
		Возврат;
	КонецЕсли;
	
	Идентификатор = "РекомендацияПоПовышениюСкоростиРаботы";
	Дело = ТекущиеДела.Добавить();
	Дело.Идентификатор = Идентификатор;
	Дело.ЕстьДела      = ТребуетсяПоказРекомендацииПоОбъемуОперативнойПамяти();
	Дело.Важное        = Истина;
	Дело.Представление = НСтр("ru = 'Скорость работы снижена'");
	Дело.Форма         = "Обработка.РекомендацияПоПовышениюСкоростиРаботы.Форма";
	Дело.Владелец      = НСтр("ru = 'Работа приложения'");
	
КонецПроцедуры

// См. ПользователиПереопределяемый.ПриОпределенииНазначенияРолей
Процедура ПриОпределенииНазначенияРолей(НазначениеРолей) Экспорт
	
	// ТолькоДляАдминистраторовСистемы.
	НазначениеРолей.ТолькоДляАдминистраторовСистемы.Добавить(
		Метаданные.Роли.АдминистраторСистемы.Имя);
	
	НазначениеРолей.ТолькоДляАдминистраторовСистемы.Добавить(
		Метаданные.Роли.Администрирование.Имя);
	
	НазначениеРолей.ТолькоДляАдминистраторовСистемы.Добавить(
		Метаданные.Роли.ОбновлениеКонфигурацииБазыДанных.Имя);
	
	// ТолькоДляПользователейСистемы.
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.ЗапускТолстогоКлиента.Имя);
	
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.ЗапускВнешнегоСоединения.Имя);
	
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.ЗапускAutomation.Имя);
	
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.РежимТехническогоСпециалиста.Имя);
	
	НазначениеРолей.ТолькоДляПользователейСистемы.Добавить(
		Метаданные.Роли.ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок.Имя);
	
	// ТолькоДляВнешнихПользователей.
	НазначениеРолей.ТолькоДляВнешнихПользователей.Добавить(
		Метаданные.Роли.БазовыеПраваВнешнихПользователейБСП.Имя);
	
	// СовместноДляПользователейИВнешнихПользователей.
	НазначениеРолей.СовместноДляПользователейИВнешнихПользователей.Добавить(
		Метаданные.Роли.ЗапускТонкогоКлиента.Имя);
	
	НазначениеРолей.СовместноДляПользователейИВнешнихПользователей.Добавить(
		Метаданные.Роли.ЗапускВебКлиента.Имя);
	
	НазначениеРолей.СовместноДляПользователейИВнешнихПользователей.Добавить(
		Метаданные.Роли.ЗапускМобильногоКлиента.Имя);
	
	НазначениеРолей.СовместноДляПользователейИВнешнихПользователей.Добавить(
		Метаданные.Роли.ВыводНаПринтерФайлБуферОбмена.Имя);
	
	НазначениеРолей.СовместноДляПользователейИВнешнихПользователей.Добавить(
		Метаданные.Роли.СохранениеДанныхПользователя.Имя);
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриПолученииСпискаШаблонов.
Процедура ПриПолученииСпискаШаблонов(ШаблоныЗаданий) Экспорт
	
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.УдалениеУстаревшихПараметровРаботыВерсийРасширений.Имя);
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.ЗаполнениеПараметровРаботыРасширений.Имя);
	
КонецПроцедуры

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПослеЗагрузкиДанных.
Процедура ПослеЗагрузкиДанных(Контейнер) Экспорт
	
	// Фоновое обновление поставляемых профилей и параметров работы расширений.
	РегистрыСведений.ПараметрыРаботыВерсийРасширений.ВключитьЗаполнениеПараметровРаботыРасширений(Ложь, Истина);
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		РегистрыСведений.ПараметрыРаботыВерсийРасширений.ЗапуститьЗаполнениеПараметровРаботыРасширений(
			НСтр("ru = 'Запуск с ожиданием после загрузки данных области'"),
			Истина);
	КонецЕсли;
	
КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "*";
	Обработчик.Процедура = "СтандартныеПодсистемыСервер.УстановитьКонстантуНеИспользоватьРазделениеПоОбластямДанных";
	Обработчик.Приоритет = 99;
	Обработчик.ОбщиеДанные = Истина;
	Обработчик.МонопольныйРежим = Истина;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "*";
	Обработчик.Процедура = "СтандартныеПодсистемыСервер.ПометитьЗаписиКэшаВерсийНеактуальными";
	Обработчик.Приоритет = 99;
	Обработчик.ОбщиеДанные = Истина;
	Обработчик.РежимВыполнения = "Оперативно";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.Процедура = "ОбновлениеИнформационнойБазыСлужебный.НачальноеЗаполнениеПредопределенныхДанных";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.7.149";
	Обработчик.Процедура = "СтандартныеПодсистемыСервер.ВключитьКонстантуДоставлятьСерверныеОповещенияБезСистемыВзаимодействия";
	Обработчик.ОбщиеДанные = Истина;
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.РежимВыполнения = "Оперативно";
	
КонецПроцедуры

// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий
Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт

	Зависимость = Настройки.Добавить();
	Зависимость.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ОбработкаСервисовИнтеграции;
	Зависимость.РаботаетСВнешнимиРесурсами = Истина;
	
КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовИсключаемыхИзПроверки
Процедура ПриОпределенииОбъектовИсключаемыхИзПроверки(Объекты) Экспорт
	Объекты.Добавить(Метаданные.РегистрыСведений.ИдентификаторыОбъектовВерсийРасширений);
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриПериодическомПолученииДанныхКлиентаНаСервере
Процедура ПриПериодическомПолученииДанныхКлиентаНаСервере(Параметры, Результаты) Экспорт
	
	ИмяПараметра = "СтандартныеПодсистемы.БазоваяФункциональность.КонтрольДинамическогоОбновления";
	ПараметрыПроверки = Параметры.Получить(ИмяПараметра);
	Если ПараметрыПроверки = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	// ИзмененаКонфигурацияИлиРасширения
	СообщениеПользователю = Неопределено;
	ПриПериодическойПроверкеИзмененаКонфигурацияИлиРасширения(СообщениеПользователю);
	Если СообщениеПользователю = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Результаты.Вставить(ИмяПараметра, СообщениеПользователю);
	
КонецПроцедуры

// См. ПользователиПереопределяемый.ПриПолученииПрочихНастроек.
Процедура ПриПолученииПрочихНастроек(СведенияОПользователе, Настройки) Экспорт
	
	ТекущееРасписание = ОбщегоНазначения.ХранилищеСистемныхНастроекЗагрузить("КонтрольДинамическогоОбновления",
		"РасписаниеПроверкиПатчей",,,
		СведенияОПользователе.ИмяПользователяИнформационнойБазы);
	Если ТекущееРасписание <> Неопределено Тогда
		СвойстваНастройки = Новый Структура;
		СвойстваНастройки.Вставить("НазваниеНастройки", НСтр("ru = 'Расписание проверки новых патчей'"));
		СвойстваНастройки.Вставить("КартинкаНастройки", БиблиотекаКартинок.Календарь);
		СвойстваНастройки.Вставить("СписокНастроек", Новый СписокЗначений);
		СвойстваНастройки.СписокНастроек.Добавить(ТекущееРасписание);
		Настройки.Вставить("РасписаниеПроверкиПатчей", СвойстваНастройки);
	КонецЕсли;
	
КонецПроцедуры

// См. ПользователиПереопределяемый.ПриСохраненииПрочихНастроек.
Процедура ПриСохраненииПрочихНастроек(СведенияОПользователе, Настройки) Экспорт
	
	Если Настройки.ИдентификаторНастройки = "РасписаниеПроверкиПатчей" Тогда
		Если Настройки.ЗначениеНастройки.Количество() = 1 Тогда
			Расписание = Настройки.ЗначениеНастройки[0].Значение;
			
			ОбщегоНазначения.ХранилищеСистемныхНастроекСохранить("КонтрольДинамическогоОбновления", "РасписаниеПроверкиПатчей",
				Расписание,,
				СведенияОПользователе.ИмяПользователяИнформационнойБазы);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// См. ПользователиПереопределяемый.ПриУдаленииПрочихНастроек.
Процедура ПриУдаленииПрочихНастроек(СведенияОПользователе, Настройки) Экспорт
	
	Если Настройки.ИдентификаторНастройки = "РасписаниеПроверкиПатчей" Тогда
		ОбщегоНазначения.ХранилищеСистемныхНастроекУдалить("КонтрольДинамическогоОбновления",
			"РасписаниеПроверкиПатчей",
			СведенияОПользователе.ИмяПользователяИнформационнойБазы);
	КонецЕсли;
	
КонецПроцедуры

// Формирует текст для вывода пользователю при необходимости динамического обновления.
// 
// Параметры:
//  ДинамическиеИзмененияКонфигурации - см. Справочники.ВерсииРасширений.ДинамическиИзмененныеРасширения
//  
// Возвращаемое значение:
//  Строка 
//
Функция ТекстСообщенияПриДинамическомОбновлении(ДинамическиеИзмененияКонфигурации) Экспорт
	
	Сообщения = Новый Массив;
	
	Если ДинамическиеИзмененияКонфигурации.КонфигурацияБазыДанныхИзмененаДинамически Тогда
		ТекстСообщенияКонфигурация = НСтр("ru = 'Версия приложения обновлена (внесены изменения в конфигурацию информационной базы).'");
		Сообщения.Добавить(ТекстСообщенияКонфигурация);
	КонецЕсли;
	
	Если ДинамическиеИзмененияКонфигурации.Исправления <> Неопределено Тогда
		Если ДинамическиеИзмененияКонфигурации.Исправления.Добавлено > 0
			И ДинамическиеИзмененияКонфигурации.Исправления.Удалено > 0 Тогда
			ТекстСообщенияПатчи = НСтр("ru = 'Новые исправления (патчи): %1, удалены: %2.'");
		ИначеЕсли ДинамическиеИзмененияКонфигурации.Исправления.Добавлено = 1 Тогда
			ТекстСообщенияПатчи = НСтр("ru = 'Новое исправление (патч).'");
		ИначеЕсли ДинамическиеИзмененияКонфигурации.Исправления.Добавлено > 0 Тогда
			ТекстСообщенияПатчи = НСтр("ru = 'Новые исправления (патчи): %1.'");
		ИначеЕсли ДинамическиеИзмененияКонфигурации.Исправления.Удалено > 0 Тогда
			ТекстСообщенияПатчи = НСтр("ru = 'Удалены исправления (патчи): %2.'");
		КонецЕсли;
		ТекстСообщенияПатчи = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщенияПатчи,
			ДинамическиеИзмененияКонфигурации.Исправления.Добавлено,
			ДинамическиеИзмененияКонфигурации.Исправления.Удалено);
		Сообщения.Добавить(ТекстСообщенияПатчи);
	КонецЕсли;
	
	Если ДинамическиеИзмененияКонфигурации.Расширения <> Неопределено Тогда
		Если ДинамическиеИзмененияКонфигурации.Расширения.Добавлено > 0 Тогда
			ТекстСообщенияРасширения = НСтр("ru = 'Новые расширения: %1.'");
			ТекстСообщенияРасширения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщенияРасширения,
				ДинамическиеИзмененияКонфигурации.Расширения.Добавлено);
			Сообщения.Добавить(ТекстСообщенияРасширения);
		КонецЕсли;
		
		Если ДинамическиеИзмененияКонфигурации.Расширения.Удалено > 0 Тогда
			ТекстСообщенияРасширения = НСтр("ru = 'Удалены расширения: %1.'");
			ТекстСообщенияРасширения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщенияРасширения,
				ДинамическиеИзмененияКонфигурации.Расширения.Удалено);
			Сообщения.Добавить(ТекстСообщенияРасширения);
		КонецЕсли;
		
		Если ДинамическиеИзмененияКонфигурации.Расширения.Изменено > 0 Тогда
			ТекстСообщенияРасширения = НСтр("ru = 'Изменены расширения: %1.'");
			ТекстСообщенияРасширения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщенияРасширения,
				ДинамическиеИзмененияКонфигурации.Расширения.Изменено);
			Сообщения.Добавить(ТекстСообщенияРасширения);
		КонецЕсли;
	КонецЕсли;
		
	Возврат СтрСоединить(Сообщения, Символы.ПС);
	
КонецФункции

// Определяет формат сохранения в PDF в зависимости от используемой платформы.
// 
// Возвращаемое значение:
//  ТипФайлаТабличногоДокумента.
//
Функция ТипФайлаТабличногоДокументаPDF() Экспорт
	
	Возврат ТипФайлаТабличногоДокумента["PDF_A_3"];
	
КонецФункции

// Определяет пользовательское представление формата сохранения в PDF в зависимости от используемой платформы.
// 
// Возвращаемое значение:
//  Строка.
//
Функция ПредставлениеТипаФайлаТабличногоДокументаPDF() Экспорт
	
	Возврат НСтр("ru = 'Документ PDF/A (.pdf)'");
	
КонецФункции

Функция ЯзыкиКонфигурации() Экспорт
	
	Языки = Новый Массив;
	Для каждого Язык Из Метаданные.Языки Цикл
		Языки.Добавить(Язык.КодЯзыка);
	КонецЦикла;
	
	Возврат Языки;
	
КонецФункции

// Параметры:
//  Заголовки - Соответствие - см. в синтакс-помощнике описание параметра Заголовки объекта HTTPОтвет.
// 
// Возвращаемое значение:
//  Соответствие
//
Функция HTTPЗаголовкиВНижнийРегистр(Заголовки) Экспорт
	
	Результат = Новый Соответствие;
	Для каждого Заголовок Из Заголовки Цикл
		Результат.Вставить(НРег(Заголовок.Ключ), Заголовок.Значение);
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Идентификатор - Строка - идентификатор компоненты.
//  Местоположение - Строка - местоположение макета компоненты (без указания версии).
//  ВнешняяКомпонента - Неопределено
//                    - Структура - данные внешней компоненты:
//                       * Идентификатор - Строка - идентификатор компоненты в справочнике.
//                       * Версия - Строка - версия.
//                       * Местоположение - Строка - местоположение.
//                       * Доступна - Булево - признак доступности.
//
// Возвращаемое значение:
//  Структура:
//   * Идентификатор - Строка - идентификатор компоненты в справочнике.
//   * Местоположение - Строка - макет компоненты, адрес ссылки в справочнике.
//   * Версия - Строка - версия.
//
Функция КомпонентаПоследнейВерсии(Идентификатор, Местоположение, ВнешняяКомпонента = Неопределено) Экспорт
		
	КомпонентаПоследнейВерсии = Новый Структура;
	КомпонентаПоследнейВерсии.Вставить("Идентификатор", Идентификатор);
	КомпонентаПоследнейВерсии.Вставить("Местоположение", "");
	КомпонентаПоследнейВерсии.Вставить("Версия", "");
	
	// Информация о внешней компоненте.
	Если ВнешняяКомпонента <> Неопределено И ВнешняяКомпонента.Доступна Тогда
		ПоследняяВерсияВнешнейКомпоненты = Новый Структура("Версия, Местоположение", 
			ВнешняяКомпонента.Версия, ВнешняяКомпонента.Местоположение);
	Иначе
		ПоследняяВерсияВнешнейКомпоненты = Неопределено;
	КонецЕсли;
	
	// Информация о компоненте из макета.
	Если ЗначениеЗаполнено(Местоположение) Тогда
		ПоследняяВерсияКомпонентыИзМакета = СтандартныеПодсистемыПовтИсп.ПоследняяВерсияКомпонентыИзМакета(
			Местоположение);
	Иначе
		ПоследняяВерсияКомпонентыИзМакета = Неопределено;
	КонецЕсли;
	
	Если ПоследняяВерсияВнешнейКомпоненты <> Неопределено И ПоследняяВерсияКомпонентыИзМакета <> Неопределено Тогда
		ЧастиВерсии = СтрРазделить(ПоследняяВерсияВнешнейКомпоненты.Версия, ".");
		Если ЧастиВерсии.Количество() = 4 Тогда
			Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ПоследняяВерсияВнешнейКомпоненты.Версия,
					ПоследняяВерсияКомпонентыИзМакета.Версия) > 0 Тогда
				ЗаполнитьЗначенияСвойств(КомпонентаПоследнейВерсии, ПоследняяВерсияВнешнейКомпоненты);
			Иначе
				ЗаполнитьЗначенияСвойств(КомпонентаПоследнейВерсии, ПоследняяВерсияКомпонентыИзМакета);
			КонецЕсли;
		Иначе
			// Если номер версии компоненты не соответствует шаблону, используется компонента из справочника.
			ЗаполнитьЗначенияСвойств(КомпонентаПоследнейВерсии, ПоследняяВерсияВнешнейКомпоненты);
		КонецЕсли;
		Возврат КомпонентаПоследнейВерсии;
	ИначеЕсли ПоследняяВерсияКомпонентыИзМакета <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(КомпонентаПоследнейВерсии, ПоследняяВерсияКомпонентыИзМакета);
		Возврат КомпонентаПоследнейВерсии;
	ИначеЕсли ПоследняяВерсияВнешнейКомпоненты <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(КомпонентаПоследнейВерсии, ПоследняяВерсияВнешнейКомпоненты);
		Возврат КомпонентаПоследнейВерсии;
	КонецЕсли;
	
	ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru='Не существует внешняя компонента с идентификатором %1'"), Идентификатор);
	
КонецФункции

// Возвращаемое значение:
//  Строка -  техническая информация о версиях подсистем и расширениях
//
Функция ТехническаяИнформацияОВерсияхПодсистемИРасширениях() Экспорт
	
	ОписанияПодсистем = ОбщегоНазначения.ОписанияПодсистем();
	
	ТехническаяИнформацияОВерсияхПодсистемИРасширениях = НСтр("ru = 'Версии подсистем'") + ":" + Символы.ПС;
	Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем Цикл
		ТехническаяИнформацияОВерсияхПодсистемИРасширениях = ТехническаяИнформацияОВерсияхПодсистемИРасширениях
			+ ОписаниеПодсистемы.Имя + " - "
			+ ОписаниеПодсистемы.Версия + Символы.ПС;
	КонецЦикла;
		
	ТехническаяИнформацияОВерсияхПодсистемИРасширениях = ТехническаяИнформацияОВерсияхПодсистемИРасширениях + Символы.ПС;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	Расширения = РасширенияКонфигурации.Получить();
	Для Каждого Расширение Из Расширения Цикл
		
		ТехническаяИнформацияОВерсияхПодсистемИРасширениях = ТехническаяИнформацияОВерсияхПодсистемИРасширениях
			+ Расширение.Имя + " - " + Расширение.Синоним + " - "
			+ Формат(Расширение.Активно, НСтр("ru = 'БЛ=Отключено; БИ=Включено'")) + Символы.ПС;
		
	КонецЦикла;
	
	Возврат ТехническаяИнформацияОВерсияхПодсистемИРасширениях;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
//
// Параметры:
//   см. описание обработчика события ПриОтправкеДанныхГлавному() в синтакс-помощнике.
// 
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Знач Получатель)
	
	Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	// Отправка идентификаторов объектов метаданных выполняется в другой секции сообщения обмена.
	ИгнорироватьОтправкуИдентификаторовОбъектовМетаданных(ЭлементДанных, ОтправкаЭлемента);
	Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
		Возврат;
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель);
	
	// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
	ОбщегоНазначенияПереопределяемый.ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
		МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
		МодульОбменДаннымиСервер.РассчитатьПроцентВыгрузкиРИБ(Получатель, Ложь);
	КонецЕсли;
	
КонецПроцедуры

// Заполняет структуру параметров, необходимых для работы клиентского кода
// данной подсистемы при запуске конфигурации, т.е. в обработчиках событий.
// - ПередНачаломРаботыСистемы,
// - ПриНачалеРаботыСистемы.
//
// Важно: при запуске недопустимо использовать команды сброса кэша
// повторно используемых модулей, иначе запуск может привести
// к непредсказуемым ошибкам и лишним серверным вызовам.
//
// Параметры:
//   Параметры   - Структура - структура параметров.
//
// Возвращаемое значение:
//   Булево   - Ложь, если дальнейшее заполнение параметров необходимо прервать.
//
Функция ДобавитьПараметрыРаботыКлиентаПриЗапуске(Параметры) Экспорт
	
	ЭтоВызовПередНачаломРаботыСистемы = Параметры.ПолученныеПараметрыКлиента <> Неопределено;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		ЭтоРазделеннаяКонфигурация = МодульРаботаВМоделиСервиса.ЭтоРазделеннаяКонфигурация();
	Иначе
		ЭтоРазделеннаяКонфигурация = Ложь;
	КонецЕсли;
	
	// Обязательные параметры для продолжения работы.
	Параметры.Вставить("РазделениеВключено", ОбщегоНазначения.РазделениеВключено());
	Параметры.Вставить("ДоступноИспользованиеРазделенныхДанных", 
		ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных());
	Параметры.Вставить("ЭтоРазделеннаяКонфигурация", ЭтоРазделеннаяКонфигурация);
	// Устарел. Для обратной совместимости. Следует использовать ПользователиКлиент.ЭтоПолноправныйПользователь.
	Параметры.Вставить("ЕстьДоступДляОбновленияВерсииПлатформы", Пользователи.ЭтоПолноправныйПользователь(,Истина));
	
	Параметры.Вставить("ИменаПодсистем", СтандартныеПодсистемыПовтИсп.ИменаПодсистем());
	Параметры.Вставить("ЭтоБазоваяВерсияКонфигурации", ЭтоБазоваяВерсияКонфигурации());
	Параметры.Вставить("ЭтоУчебнаяПлатформа", ЭтоУчебнаяПлатформа());
	Параметры.Вставить("ИмяТекущегоПользователя", ТекущийПользователь().Имя);
	// Устарел. Для обратной совместимости. Следует использовать ОбщегоНазначенияКлиентСервер.ИмяCOMСоединителя.
	Параметры.Вставить("ИмяCOMСоединителя", ОбщегоНазначенияКлиентСервер.ИмяCOMСоединителя());
	Параметры.Вставить("КодОсновногоЯзыка", ОбщегоНазначения.КодОсновногоЯзыка());
	
	Параметры.Вставить("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", ЗапрашиватьПодтверждениеПриЗавершенииПрограммы());
	
	ОбщиеПараметры = ОбщегоНазначения.ОбщиеПараметрыБазовойФункциональности();
	Параметры.Вставить("МинимальнаяВерсияПлатформы",   ОбщиеПараметры.МинимальнаяВерсияПлатформы);
	Параметры.Вставить("РекомендуемаяВерсияПлатформы", ОбщиеПараметры.РекомендуемаяВерсияПлатформы);
	// Устарели. Для обратной совместимости. Следует использовать два предыдущих параметра.
	Параметры.Вставить("МинимальноНеобходимаяВерсияПлатформы", ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы);
	Параметры.Вставить("РаботаВПрограммеЗапрещена",            ОбщиеПараметры.РаботаВПрограммеЗапрещена);
	
	Параметры.Вставить("РекомендуемыйОбъемОперативнойПамяти", ОбщиеПараметры.РекомендуемыйОбъемОперативнойПамяти);
	Параметры.Вставить("ТребуетсяПоказРекомендацииПоОбъемуОперативнойПамяти", ТребуетсяПоказРекомендацииПоОбъемуОперативнойПамяти()
		И Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ТекущиеДела"));
	
	Параметры.Вставить("ЭтоСеансВнешнегоПользователя", Пользователи.ЭтоСеансВнешнегоПользователя());
	Параметры.Вставить("ЭтоПолноправныйПользователь",  Пользователи.ЭтоПолноправныйПользователь());
	Параметры.Вставить("ЭтоАдминистраторСистемы",      Пользователи.ЭтоПолноправныйПользователь(, Истина));
	Параметры.Вставить("ИнформационнаяБазаФайловая",   ОбщегоНазначения.ИнформационнаяБазаФайловая());
	
	Если ИспользуетсяНедопустимаяВерсияПлатформы() Тогда
		Параметры.Вставить("ИспользуетсяНедопустимаяВерсияПлатформы");
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы Тогда
		Параметры.Вставить("ЭлементыСтиля", НаборЭлементовСтиля());
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И Не Параметры.ПолученныеПараметрыКлиента.Свойство("ОпцииИнтерфейса") Тогда
		Параметры.Вставить("ОпцииИнтерфейса", СтандартныеПодсистемыПовтИсп.ОпцииИнтерфейса());
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы Тогда
		ОшибкаНедостаточноПравДляВходаВПрограмму = ПользователиСлужебный.ОшибкаНедостаточноПравДляВходаВПрограмму(
			Не Параметры.ПолученныеПараметрыКлиента.Свойство("ОшибкаНедостаточноПравДляВходаВПрограмму"));
		
		Если ЗначениеЗаполнено(ОшибкаНедостаточноПравДляВходаВПрограмму) Тогда
			Параметры.Вставить("ОшибкаНедостаточноПравДляВходаВПрограмму", ОшибкаНедостаточноПравДляВходаВПрограмму);
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
		
		МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщегоНазначения.ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
		МодульБлокировкаРаботыСВнешнимиРесурсами.ПриДобавленииПараметровРаботыКлиентаПриЗапуске(
			Параметры, ЭтоВызовПередНачаломРаботыСистемы);
		
		Если РегламентныеЗаданияСервер.РаботаСВнешнимиРесурсамиЗаблокирована() Тогда
			Параметры.Вставить("РаботаСВнешнимиРесурсамиЗаблокирована");
		КонецЕсли;
		
	КонецЕсли;
	
	Если Не ОбновлениеИнформационнойБазыСлужебный.ДобавитьПараметрыРаботыКлиентаПриЗапуске(Параметры)
	   И ЭтоВызовПередНачаломРаботыСистемы Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И Не Параметры.ПолученныеПараметрыКлиента.Свойство("ПоказатьНерекомендуемуюВерсиюПлатформы")
	   И ПоказатьНерекомендуемуюВерсиюПлатформы(Параметры) Тогда
		
		Параметры.Вставить("ПоказатьНерекомендуемуюВерсиюПлатформы");
		СтандартныеПодсистемыВызовСервера.СкрытьРабочийСтолПриНачалеРаботыСистемы();
		Возврат Ложь;
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И Не Параметры.ПолученныеПараметрыКлиента.Свойство("ВосстановитьСвязьСГлавнымУзлом")
	   И Не ОбщегоНазначения.РазделениеВключено() Тогда
	   
		УстановитьПривилегированныйРежим(Истина);
		ВосстановитьСвязьСГлавнымУзлом = ПланыОбмена.ГлавныйУзел() = Неопределено
			И ЗначениеЗаполнено(Константы.ГлавныйУзел.Получить());
		УстановитьПривилегированныйРежим(Ложь);
	   
		Если ВосстановитьСвязьСГлавнымУзлом Тогда 
			Параметры.Вставить("ВосстановитьСвязьСГлавнымУзлом", Пользователи.ЭтоПолноправныйПользователь(, Истина));
			СтандартныеПодсистемыВызовСервера.СкрытьРабочийСтолПриНачалеРаботыСистемы();
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И Не Параметры.ПолученныеПараметрыКлиента.Свойство("ВыбратьНачальныеРегиональныеНастройкиИБ")
	   И ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы() Тогда
		
		Параметры.Вставить("ВыбратьНачальныеРегиональныеНастройкиИБ",
			Пользователи.ЭтоПолноправныйПользователь(, Истина, Ложь));
		СтандартныеПодсистемыВызовСервера.СкрытьРабочийСтолПриНачалеРаботыСистемы();
		Возврат Ложь;
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы И ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса") Тогда
		
		ОписаниеОшибки = "";
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		МодульРаботаВМоделиСервиса.ПриПроверкеБлокировкиОбластиДанныхПриЗапуске(ОписаниеОшибки);
		Если Не ПустаяСтрока(ОписаниеОшибки) Тогда
			Параметры.Вставить("ОбластьДанныхЗаблокирована", ОписаниеОшибки);
			// Работа будет завершена.
			Возврат Ложь;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И Не Параметры.ПолученныеПараметрыКлиента.Свойство("СерверныеОповещения") Тогда
		
		СерверныеОповещения.ПриДобавленииПараметровРаботыКлиентаПриЗапуске(Параметры);
	КонецЕсли;
	
	Если ПараметрыСеанса.ВыполняетсяОбновлениеИБ <> Неопределено // Обязательная инициализация параметра сеанса.
		И Не Параметры.РазделениеВключено
		И ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы()
		И ОбновлениеИнформационнойБазыСлужебный.СтатусНевыполненныхОбработчиков(Истина) = "СтатусНеВыполнено" Тогда
		Параметры.Вставить("НеобходимоВыполнитьОбработчикиОтложенногоОбновления");
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
		МодульРаботаВБезопасномРежимеСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежимеСлужебный");
		МодульРаботаВБезопасномРежимеСлужебный.ПриДобавленииПараметровРаботыКлиентаПриЗапуске(Параметры, Истина);
	КонецЕсли;
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И НЕ Параметры.ПолученныеПараметрыКлиента.Свойство("ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском")
	   И ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()
	   И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
		
		МодульОбменДаннымиСлужебный = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСлужебный");
		Если МодульОбменДаннымиСлужебный.ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском() Тогда
			Параметры.Вставить("ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском");
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	// Проверка необходимости предварительного обновления параметров работы программы.
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И Не Параметры.ПолученныеПараметрыКлиента.Свойство("НеобходимоОбновлениеПараметровРаботыПрограммы")
	   И Не Параметры.Свойство("УпрощеннаяФормаОбновленияИБ") Тогда
		
		НастройкаПодчиненногоУзлаРИБ = Ложь;
		Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление(НастройкаПодчиненногоУзлаРИБ) Тогда
			// Будет выполнено предварительное обновление.
			Параметры.Вставить("НеобходимоОбновлениеПараметровРаботыПрограммы");
			
			Если НастройкаПодчиненногоУзлаРИБ
			   И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
				
				ШаблонОшибки =
					НСтр("ru = 'Не удалось установить монопольный режим для настройки узла РИБ по причине:
					           |%1'");
				УстановитьМонопольныйРежимПриЗапуске(Истина, ШаблонОшибки);
			КонецЕсли;
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	// Обязательные параметры для всех режимов работы.
	Параметры.Вставить("ПодробнаяИнформация", Метаданные.ПодробнаяИнформация);
	
	Если ОбновлениеИнформационнойБазыСлужебный.НеобходимоОбновлениеНеразделенныхДанныхИнформационнойБазы() Тогда
		Параметры.Вставить("НеобходимоОбновлениеНеразделенныхДанныхИнформационнойБазы");
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
		МодульРаботаВБезопасномРежимеСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежимеСлужебный");
		МодульРаботаВБезопасномРежимеСлужебный.ПриДобавленииПараметровРаботыКлиентаПриЗапуске(Параметры);
	КонецЕсли;
	
	Если Не Параметры.ДоступноИспользованиеРазделенныхДанных Тогда
		Возврат Истина;
	КонецЕсли;
	
	// Параметры для работы в локальном режиме или
	// в сеансе с установленными значениями разделителей в модели сервиса.
	
	Если ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы() Тогда
		Параметры.Вставить("НеобходимоОбновлениеИнформационнойБазы");
		СтандартныеПодсистемыВызовСервера.СкрытьРабочийСтолПриНачалеРаботыСистемы();
	КонецЕсли;
	
	Если Не Параметры.РазделениеВключено
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
		
		МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
		Если МодульОбменДаннымиСервер.ЗагрузитьСообщениеОбменаДанными() Тогда
			Параметры.Вставить("ЗагрузитьСообщениеОбменаДанными");
		КонецЕсли;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса") Тогда
		МодульАвтономнаяРабота = ОбщегоНазначения.ОбщийМодуль("АвтономнаяРабота");
		Если МодульАвтономнаяРабота.ПродолжитьНастройкуАвтономногоРабочегоМеста(Параметры) Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Отказ = Ложь;
	Если ЭтоВызовПередНачаломРаботыСистемы Тогда
		ПользователиСлужебный.ПриДобавленииПараметровРаботыКлиентаПриЗапуске(Параметры, Отказ, Истина);
	КонецЕсли;
	Если Отказ Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ДобавитьОбщиеПараметрыРаботыКлиента(Параметры);
	
	Если ЭтоВызовПередНачаломРаботыСистемы
	   И (Параметры.Свойство("НеобходимоОбновлениеИнформационнойБазы")
	      Или ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы()) Тогда
		// Не следует добавлять остальные параметры до окончания обновления ИБ,
		// так как они могут рассчитывать, что обновление ИБ уже выполнено.
		Возврат Ложь;
	КонецЕсли;
	
	УстановитьМонопольныйРежимПриЗапуске(Ложь);
	
	Возврат Истина;
	
КонецФункции

// Заполняет структуру параметров, необходимых для работы клиентского кода
// данной подсистемы. 
//
// Параметры:
//   Параметры - Структура
//
Процедура ДобавитьПараметрыРаботыКлиента(Параметры)
	
	Параметры.Вставить("ИменаПодсистем", СтандартныеПодсистемыПовтИсп.ИменаПодсистем());
	Параметры.Вставить("ДоступноИспользованиеРазделенныхДанных",
		ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных());
	Параметры.Вставить("РазделениеВключено", ОбщегоНазначения.РазделениеВключено());
	
	// Устарел. Следует использовать СтандартныеПодсистемыКлиент.ЭтоБазоваяВерсияКонфигурации.
	Параметры.Вставить("ЭтоБазоваяВерсияКонфигурации", ЭтоБазоваяВерсияКонфигурации());
	// Устарел. Следует использовать СтандартныеПодсистемыКлиент.ЭтоУчебнаяПлатформа.
	Параметры.Вставить("ЭтоУчебнаяПлатформа", ЭтоУчебнаяПлатформа());
	// Устарел. Следует использовать ОбщегоНазначенияКлиентСервер.ИмяCOMСоединителя.
	Параметры.Вставить("ИмяCOMСоединителя", ОбщегоНазначенияКлиентСервер.ИмяCOMСоединителя());
	Параметры.Вставить("ЭлементыСтиля", НаборЭлементовСтиля());
	
	ДобавитьОбщиеПараметрыРаботыКлиента(Параметры);
	
	Параметры.Вставить("ИмяКонфигурации",     Метаданные.Имя);
	Параметры.Вставить("СинонимКонфигурации", Метаданные.Синоним);
	Параметры.Вставить("ВерсияКонфигурации",  Метаданные.Версия);
	Параметры.Вставить("ПодробнаяИнформация", Метаданные.ПодробнаяИнформация);
	Параметры.Вставить("КодОсновногоЯзыка",   ОбщегоНазначения.КодОсновногоЯзыка());
	
	Параметры.Вставить("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы",
		ЗапрашиватьПодтверждениеПриЗавершенииПрограммы());
	
	Параметры.Вставить("ИнформационнаяБазаФайловая", ОбщегоНазначения.ИнформационнаяБазаФайловая());
	
	Если РегламентныеЗаданияСервер.РаботаСВнешнимиРесурсамиЗаблокирована() Тогда
		Параметры.Вставить("РаботаСВнешнимиРесурсамиЗаблокирована");
	КонецЕсли;
	
	Параметры.Вставить("ВерсияРежимаСовместимости", ВерсияРежимаСовместимости());
	
КонецПроцедуры

// Заполняет структуру параметров, необходимых для работы клиентского кода
// при запуске конфигурации и в дальнейшем во время работы с ней. 
//
// Параметры:
//   Параметры   - Структура - структура параметров.
//
Процедура ДобавитьОбщиеПараметрыРаботыКлиента(Параметры)
	
	Если Не Параметры.РазделениеВключено Или Параметры.ДоступноИспользованиеРазделенныхДанных Тогда
		
		УстановитьПривилегированныйРежим(Истина);
		Параметры.Вставить("АвторизованныйПользователь", Пользователи.АвторизованныйПользователь());
		Параметры.Вставить("ЗаголовокПриложения", СокрЛП(Константы.ЗаголовокСистемы.Получить()));
		УстановитьПривилегированныйРежим(Ложь);
		
	КонецЕсли;
	
	Параметры.Вставить("ЭтоГлавныйУзел", НЕ ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ());
	
	Параметры.Вставить("ТребуетсяОбновлениеКонфигурацииУзлаРИБ",
		ОбщегоНазначения.ТребуетсяОбновлениеКонфигурацииПодчиненногоУзлаРИБ());
	
КонецПроцедуры

// Возвращает номера версий, поддерживаемых программным интерфейсом ИмяИнтерфейса.
// См. ОбщегоНазначения.ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение.
//
// Параметры:
//   ИмяИнтерфейса - Строка - имя программного интерфейса.
//
// Возвращаемое значение:
//  Массив - список версий типа Строка.
//
Функция ПоддерживаемыеВерсии(ИмяИнтерфейса) Экспорт
	
	МассивВерсий = Неопределено;
	СтруктураПоддерживаемыхВерсий = Новый Структура;
	
	ИнтеграцияПодсистемБСП.ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(СтруктураПоддерживаемыхВерсий);
	СтруктураПоддерживаемыхВерсий.Свойство(ИмяИнтерфейса, МассивВерсий);
	
	Если МассивВерсий = Неопределено Тогда
		Возврат ОбщегоНазначения.ЗначениеВСтрокуXML(Новый Массив);
	Иначе
		Возврат ОбщегоНазначения.ЗначениеВСтрокуXML(МассивВерсий);
	КонецЕсли;
	
КонецФункции

// Устанавливает общую форму ПустойРабочийСтол на рабочий стол.
Процедура УстановитьПустуюФормуНаРабочийСтол() Экспорт
	
	КлючОбъекта = "Общее/НастройкиНачальнойСтраницы";
	ТекущиеНастройки = ХранилищеСистемныхНастроек.Загрузить(КлючОбъекта);
	
	Если ТипЗнч(ТекущиеНастройки) = Тип("НастройкиНачальнойСтраницы") Тогда
		ТекущийСоставФорм = ТекущиеНастройки.ПолучитьСоставФорм();
		Если ТекущийСоставФорм.ПраваяКолонка.Количество() = 0
		   И ТекущийСоставФорм.ЛеваяКолонка.Количество() = 1
		   И ТекущийСоставФорм.ЛеваяКолонка[0] = "ОбщаяФорма.ПустойРабочийСтол" Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	СоставФорм = Новый СоставФормНачальнойСтраницы;
	СоставФорм.ЛеваяКолонка.Добавить("ОбщаяФорма.ПустойРабочийСтол");
	Настройки = Новый НастройкиНачальнойСтраницы;
	Настройки.УстановитьСоставФорм(СоставФорм);
	ХранилищеСистемныхНастроек.Сохранить(КлючОбъекта, "", Настройки);
	
КонецПроцедуры

// Параметры:
//  Установить - Булево
//  ШаблонОшибки - Строка
//
Процедура УстановитьМонопольныйРежимПриЗапуске(Установить, ШаблонОшибки = "")
	
	Если Установить И МонопольныйРежим() Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПараметра = "УстановленМонопольныйРежимПриЗапуске";
	
	УстановитьПривилегированныйРежим(Истина);
	Если Установить Тогда
		Попытка
			УстановитьМонопольныйРежим(Истина);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки,
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
			ВызватьИсключение ТекстОшибки;
		КонецПопытки;
		
		ТекущиеПараметры = Новый Соответствие(ПараметрыСеанса.ПараметрыКлиентаНаСервере);
		ТекущиеПараметры.Вставить(ИмяПараметра, Истина);
		ПараметрыСеанса.ПараметрыКлиентаНаСервере = Новый ФиксированноеСоответствие(ТекущиеПараметры);
		
	ИначеЕсли ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить(ИмяПараметра) <> Неопределено Тогда
		
		Если МонопольныйРежим() Тогда
			УстановитьМонопольныйРежим(Ложь);
		КонецЕсли;
		
		ТекущиеПараметры = Новый Соответствие(ПараметрыСеанса.ПараметрыКлиентаНаСервере);
		ТекущиеПараметры.Вставить(ИмяПараметра, Истина);
		ПараметрыСеанса.ПараметрыКлиентаНаСервере = Новый ФиксированноеСоответствие(ТекущиеПараметры);
	КонецЕсли;
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

// Обработчик одноименного регламентного задания.
//
Процедура ОбработкаСервисовИнтеграции() Экспорт
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.ОбработкаСервисовИнтеграции);
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	СервисыИнтеграции.ВыполнитьОбработку();
КонецПроцедуры

// Параметры:
//  ИмяПользователя - Строка
//
// Возвращаемое значение:
//  Булево
//
Функция ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммыДляПользователя(ИмяПользователя = Неопределено)
	
	Результат = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(
		"ОбщиеНастройкиПользователя", 
		"ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы",,,
		ИмяПользователя);
	
	Если Результат = Неопределено Тогда
		Результат = Истина;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обновление информационной базы.

// Устанавливает значение константам НеИспользоватьРазделениеПоОбластямДанных и
// СтандартныеПодсистемыВАвтономномРежиме на основании значения ИспользоватьРазделениеПоОбластямДанных.
//
Процедура УстановитьКонстантуНеИспользоватьРазделениеПоОбластямДанных(Параметры) Экспорт
	
	НовыеЗначения = Новый Соответствие;
	Если Константы.ИспользоватьРазделениеПоОбластямДанных.Получить() Тогда
		НовыеЗначения.Вставить("НеИспользоватьРазделениеПоОбластямДанных", Ложь);
		НовыеЗначения.Вставить("СтандартныеПодсистемыВАвтономномРежиме", Ложь);
	ИначеЕсли ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() Тогда
		НовыеЗначения.Вставить("НеИспользоватьРазделениеПоОбластямДанных", Ложь);
		НовыеЗначения.Вставить("СтандартныеПодсистемыВАвтономномРежиме", Истина);
	Иначе
		НовыеЗначения.Вставить("НеИспользоватьРазделениеПоОбластямДанных", Истина);
		НовыеЗначения.Вставить("СтандартныеПодсистемыВАвтономномРежиме", Ложь);
	КонецЕсли;
	
	ЭтоОбменДаннымиВМоделиСервиса = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбменДаннымиВМоделиСервиса");
	Для каждого НовоеЗначение Из НовыеЗначения Цикл
		
		Если ЭтоОбменДаннымиВМоделиСервиса 
			И НовоеЗначение.Ключ = "СтандартныеПодсистемыВАвтономномРежиме" Тогда
			ПредыдущееЗначение = ОбщегоНазначения.ЭтоАвтономноеРабочееМесто();
			// Всегда синхронизируем константу СтандартныеПодсистемыВАвтономномРежиме с ЭтоАвтономноеРабочееМесто 
			Константы[НовоеЗначение.Ключ].Установить(НовоеЗначение.Значение); 
		Иначе
			ПредыдущееЗначение = Константы[НовоеЗначение.Ключ].Получить();
		КонецЕсли;
		
		Если ПредыдущееЗначение <> НовоеЗначение.Значение Тогда
				
			Если НЕ Параметры.МонопольныйРежим Тогда
				Параметры.МонопольныйРежим = Истина;
				Возврат; // Требуется изменение значения, поэтому монопольный режим.
			КонецЕсли;
				
			Константы[НовоеЗначение.Ключ].Установить(НовоеЗначение.Значение);
			
			Если ЭтоОбменДаннымиВМоделиСервиса
				И НовоеЗначение.Ключ = "СтандартныеПодсистемыВАвтономномРежиме" 
				И ПредыдущееЗначение Тогда
				МодульАвтономнаяРабота = ОбщегоНазначения.ОбщийМодуль("АвтономнаяРабота");
				МодульАвтономнаяРабота.ВыключитьСвойствоИБ();
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Сбрасывает дату обновления всех записей кэша версий, таким
// образом все записи кэша начинают считаться неактуальными.
//
Процедура ПометитьЗаписиКэшаВерсийНеактуальными() Экспорт
	
	НачатьТранзакцию();
	Попытка
		НаборЗаписей = РегистрыСведений.КэшПрограммныхИнтерфейсов.СоздатьНаборЗаписей();
		
		Блокировка = Новый БлокировкаДанных;
		Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
		Блокировка.Заблокировать();
		
		НаборЗаписей.Прочитать();
		Для каждого Запись Из НаборЗаписей Цикл
			Запись.ДатаОбновления = Неопределено;
		КонецЦикла;
		
		ОбновлениеИнформационнойБазы.ЗаписатьДанные(НаборЗаписей);
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура ВключитьКонстантуДоставлятьСерверныеОповещенияБезСистемыВзаимодействия() Экспорт
	
	Константы.ДоставлятьСерверныеОповещенияБезСистемыВзаимодействия.Установить(Истина);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.
Процедура ПриДобавленииПереименованийОбъектовМетаданных(Итог) Экспорт
	
	Библиотека = "СтандартныеПодсистемы";
	
	СтароеИмя = "Роль.БазовыеПрава";
	НовоеИмя  = "Роль.БазовыеПраваБСП";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "3.0.1.19", СтароеИмя, НовоеИмя, Библиотека);
	
	СтароеИмя = "Роль.БазовыеПраваВнешнегоПользователя";
	НовоеИмя  = "Роль.БазовыеПраваВнешнихПользователейБСП";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "3.0.1.19", СтароеИмя, НовоеИмя, Библиотека);
	
	СтароеИмя = "Роль.РежимВсеФункции";
	НовоеИмя  = "Роль.РежимТехническогоСпециалиста";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "3.1.5.153", СтароеИмя, НовоеИмя, Библиотека);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики подписок на события.

// Обработчик события ПередЗаписью предопределенных элементов.
Процедура ЗапретитьПометкуУдаленияПредопределенныхЭлементовПередЗаписью(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	Если Источник.ПометкаУдаления <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	ИмяРеквизита = "";
	ЗначениеРеквизита = "";
	Если Не ЭтоПредопределенныеДанные(Источник, ИмяРеквизита, ЗначениеРеквизита) Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ЭтоНовый() Тогда
		ВызватьИсключение
			НСтр("ru = 'Недопустимо создавать предопределенный элемент, помеченный на удаление.'");
	КонецЕсли;
		
	СтарыеСвойства = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Источник.Ссылка, 
		"ПометкаУдаления, ИмяПредопределенныхДанных" 
			+ ?(ИмяРеквизита <> "ИмяПредопределенныхДанных", ", " + ИмяРеквизита, ""));
	
	Если (СтарыеСвойства.ИмяПредопределенныхДанных <> "" Или ИмяРеквизита <> "" И ЗначениеЗаполнено(СтарыеСвойства[ИмяРеквизита]))
	   И СтарыеСвойства.ПометкаУдаления <> Истина Тогда
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Недопустимо помечать на удаление предопределенный элемент:
			           |""%1"".'"),
			Строка(Источник.Ссылка));
	ИначеЕсли (ЗначениеЗаполнено(ЗначениеРеквизита) И Не ЗначениеЗаполнено(СтарыеСвойства[ИмяРеквизита])
	      Или СтарыеСвойства.ИмяПредопределенныхДанных = "")
	        И СтарыеСвойства.ПометкаУдаления = Истина Тогда
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Недопустимо связывать с именем предопределенного элемент, помеченный на удаление:
			           |""%1"".'"),
			Строка(Источник.Ссылка));
	КонецЕсли;
	
КонецПроцедуры

// Обработчик события ПередУдалением предопределенных элементов.
Процедура ЗапретитьУдалениеПредопределенныхЭлементовПередУдалением(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ЭтоПредопределенныеДанные(Источник) Тогда
		Возврат;
	КонецЕсли;
	
	ЗначенияРеквизитов = Новый Структура("Владелец");
	ЗаполнитьЗначенияСвойств(ЗначенияРеквизитов, Источник);
	
	Если ЗначениеЗаполнено(ЗначенияРеквизитов.Владелец) И ЗначенияРеквизитов.Владелец.ПолучитьОбъект() = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Недопустимо удалять предопределенный элемент
			|""%1"".'"),
		Строка(Источник.Ссылка));
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработка подписок на события планов обмена РИБ.

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание параметров в обработчике события ПриОтправкеДанныхПодчиненному в синтакс-помощнике.
// 
// Параметры:
//  Источник - ПланОбменаОбъект
//  ЭлементДанных - Произвольный
//  ОтправкаЭлемента - ОтправкаЭлементаДанных
//  СозданиеНачальногоОбраза - Булево
// 
Процедура ПриОтправкеДанныхПодчиненномуСобытие(Источник, ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза) Экспорт
	
	ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Источник);
	
	Если ОтправкаЭлемента <> ОтправкаЭлементаДанных.Игнорировать Тогда
		// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
		ОбщегоНазначенияПереопределяемый.ПриОтправкеДанныхПодчиненному(Источник, ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза);
	КонецЕсли;
	
КонецПроцедуры

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание параметров в обработчике события ПриОтправкеДанныхГлавному в синтакс-помощнике.
// 
// Параметры:
//  Источник - ПланОбменаОбъект
//  ЭлементДанных - Произвольный
//  ОтправкаЭлемента - ОтправкаЭлементаДанных
//  
Процедура ПриОтправкеДанныхГлавномуСобытие(Источник, ЭлементДанных, ОтправкаЭлемента) Экспорт
	
	ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Источник);
	
	Если ОтправкаЭлемента <> ОтправкаЭлементаДанных.Игнорировать Тогда
		// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
		ОбщегоНазначенияПереопределяемый.ПриОтправкеДанныхГлавному(Источник, ЭлементДанных, ОтправкаЭлемента);
	КонецЕсли;
	
КонецПроцедуры

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание параметров в обработчике события ПриПолученииДанныхОтПодчиненного в синтакс-помощнике.
// 
// Параметры:
//  Источник - ПланОбменаОбъект
//  ЭлементДанных - Произвольный
//  ПолучениеЭлемента - ПолучениеЭлементаДанных
//  ОтправкаНазад - Булево
// 
Процедура ПриПолученииДанныхОтПодчиненногоСобытие(Источник, ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад) Экспорт
	
	ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Источник);
	
	Если ПолучениеЭлемента <> ПолучениеЭлементаДанных.Игнорировать Тогда
		// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
		ОбщегоНазначенияПереопределяемый.ПриПолученииДанныхОтПодчиненного(Источник, ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад);
	КонецЕсли;
	
КонецПроцедуры

// Процедура является обработчиком одноименного события, возникающего при обмене данными в распределенной
// информационной базе.
// См. описание обработчика события ПриПолученииДанныхОтГлавного в синтакс-помощнике.
// 
// Параметры:
//  Источник - ПланОбменаОбъект
//  ЭлементДанных - Произвольный
//  ПолучениеЭлемента - ПолучениеЭлементаДанных
//  ОтправкаНазад - Булево
//
Процедура ПриПолученииДанныхОтГлавногоСобытие(Источник, ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад) Экспорт
	
	ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Источник);
	
	Если ПолучениеЭлемента <> ПолучениеЭлементаДанных.Игнорировать Тогда
		// Вызов переопределяемого обработчика для выполнения прикладной логики обмена РИБ.
		ОбщегоНазначенияПереопределяемый.ПриПолученииДанныхОтГлавного(Источник, ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад);
	КонецЕсли;
	
КонецПроцедуры

// Процедура-обработчик подписки на событие ПередЗаписью для ПланОбменаОбъект.
// Используется для вызова обработчика события ПослеПолученияДанных при обмене в распределенной ИБ.
// 
// Параметры:
//  Источник - ПланОбменаОбъект
//  Отказ - Булево
//
Процедура ПослеПолученияДанных(Источник, Отказ) Экспорт
	
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	Если Не Источник.Метаданные().РаспределеннаяИнформационнаяБаза Тогда
		Возврат;
	КонецЕсли;
	
	Если Источник.ЭтоНовый()
		Или Источник.НомерПринятого = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "НомерПринятого") Тогда
		Возврат;
	КонецЕсли;
	
	ПолучениеИзГлавногоУзла = (ПланыОбмена.ГлавныйУзел() = Источник.Ссылка);
	ИнтеграцияПодсистемБСП.ПослеПолученияДанных(Источник, Отказ, ПолучениеИзГлавногоУзла);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ

// Возвращаемое значение:
//  Массив из ОбъектМетаданных
//
Функция ОбъектыМетаданныхВсехПредопределенныхДанных()
	
	РазделениеВключено  = ОбщегоНазначения.РазделениеВключено();
	ЭтоРазделенныйСеанс = ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
	
	КоллекцииМетаданных = Новый Массив;
	КоллекцииМетаданных.Добавить(Метаданные.Справочники);
	КоллекцииМетаданных.Добавить(Метаданные.ПланыВидовХарактеристик);
	КоллекцииМетаданных.Добавить(Метаданные.ПланыСчетов);
	КоллекцииМетаданных.Добавить(Метаданные.ПланыВидовРасчета);
	
	ОбъектыМетаданных = Новый Массив;
	
	Для Каждого Коллекция Из КоллекцииМетаданных Цикл
		Для Каждого ОбъектМетаданных Из Коллекция Цикл
			
			Если РазделениеВключено Тогда 
				
				МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
				ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ОбъектМетаданных);
				
				Если (   ЭтоРазделенныйСеанс И Не ЭтоРазделенныйОбъектМетаданных)
				 Или (Не ЭтоРазделенныйСеанс И    ЭтоРазделенныйОбъектМетаданных) Тогда 
					Продолжить;
				КонецЕсли;
				
			КонецЕсли;
			
			ОбъектыМетаданных.Добавить(ОбъектМетаданных);
		КонецЦикла;
	КонецЦикла;
	
	Возврат ОбъектыМетаданных;
	
КонецФункции

Процедура УстановитьИнициализациюВсехПредопределенныхДанных(ОбъектыМетаданных)
	
	РазделениеВключено  = ОбщегоНазначения.РазделениеВключено();
	ЭтоРазделенныйСеанс = ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
	
	Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
		Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
		Менеджер.УстановитьИнициализациюПредопределенныхДанных(Истина);
	КонецЦикла;
	
	Если Не РазделениеВключено Или Не ЭтоРазделенныйСеанс Тогда 
		УстановитьОбновлениеПредопределенныхДанныхИнформационнойБазы(ОбновлениеПредопределенныхДанных.Авто);
	КонецЕсли;
	
КонецПроцедуры

Процедура СоздатьНедостающиеПредопределенныеДанные(ОбъектыМетаданных)
	
	Запрос = Новый Запрос;
	ТекстЗапроса =
		"ВЫБРАТЬ
		|	ПсевдонимЗаданнойТаблицы.Ссылка КАК Ссылка,
		|	ПсевдонимЗаданнойТаблицы.ВерсияДанных КАК ВерсияДанных,
		|	ЕСТЬNULL(ПсевдонимЗаданнойТаблицы.Родитель.ИмяПредопределенныхДанных, """") КАК ИмяРодителя,
		|	ПсевдонимЗаданнойТаблицы.ИмяПредопределенныхДанных КАК Имя
		|ИЗ
		|	&ТекущаяТаблица КАК ПсевдонимЗаданнойТаблицы
		|ГДЕ
		|	ПсевдонимЗаданнойТаблицы.Предопределенный";
	
	ОписанияСохраненных = Новый Массив;
	ТаблицыБезСохраненных = Новый Массив;
	Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
		
		Если ОбъектМетаданных.ОбновлениеПредопределенныхДанных
				= Метаданные.СвойстваОбъектов.ОбновлениеПредопределенныхДанных.НеОбновлятьАвтоматически Тогда
			Продолжить;
		КонецЕсли;
		
		ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
		Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя);
		
		Если Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных)
		 Или Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных)
		 Или Не ОбъектМетаданных.Иерархический Тогда
			
			Запрос.Текст = СтрЗаменить(Запрос.Текст,
				"ЕСТЬNULL(ПсевдонимЗаданнойТаблицы.Родитель.ИмяПредопределенныхДанных, """")", """""");
		КонецЕсли;
		
		// АПК:1328-выкл - №648.1.1 В вызывающей процедуре установлена исключительная блокировка.
		// @skip-check query-in-loop - Порционная обработка данных
		ТаблицаИмен = Запрос.Выполнить().Выгрузить();
		// АПК:1328-вкл.
		ТаблицаИмен.Индексы.Добавить("Имя");
		Имена = ОбъектМетаданных.ПолучитьИменаПредопределенных();
		СохранитьСуществующиеПредопределенныеОбъектыПередСозданиемНедостающих(ОбъектМетаданных,
			ПолноеИмя, ТаблицаИмен, Имена, Запрос, ОписанияСохраненных, ТаблицыБезСохраненных);
	КонецЦикла;
	
	// Восстановление предопределенных элементов, существовавших до инициализации.
	Для Каждого ОписаниеСохраненных Из ОписанияСохраненных Цикл
		Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОписаниеСохраненных.ПолноеИмя);
		Менеджер.УстановитьИнициализациюПредопределенныхДанных(Ложь);
		ИнициализироватьПредопределенныеДанные();
		
		Запрос.Текст = ОписаниеСохраненных.ТекстЗапроса;
		// АПК:1328-выкл - №648.1.1 В вызывающей процедуре установлена исключительная блокировка.
		// @skip-check query-in-loop - Порционная обработка данных
		ТаблицаИмен = Запрос.Выполнить().Выгрузить();
		// АПК:1328-вкл.
		ТаблицаИмен.Индексы.Добавить("Имя");
		Для Каждого ОписаниеСохраненного Из ОписаниеСохраненных.ТаблицаИмен Цикл
			Если Не ОписаниеСохраненного.ОбъектСуществует Тогда
				Продолжить;
			КонецЕсли;
			Строка = ТаблицаИмен.Найти(ОписаниеСохраненного.Имя, "Имя");
			Если Строка <> Неопределено Тогда
				НовыйОбъект = Строка.Ссылка.ПолучитьОбъект();
				Если ОписаниеСохраненных.ЭтоПланСчетов Тогда
					Если ОписаниеСохраненного.Объект.ВерсияДанных <> Строка.ВерсияДанных Тогда
						ОбновитьОбъектСчета(ОписаниеСохраненного.Объект);
					КонецЕсли;
					ДополнитьНовыеВидыСубконтоСчета(ОписаниеСохраненного.Объект, НовыйОбъект);
				КонецЕсли;
				// АПК:1327-выкл - №648.1.1 В вызывающей процедуре установлена исключительная блокировка.
				ОбновлениеИнформационнойБазы.УдалитьДанные(НовыйОбъект);
				// АПК:1327-вкл.
				Строка.Имя = "";
			КонецЕсли;
			// АПК:1327-выкл - №648.1.1 В вызывающей процедуре установлена исключительная блокировка.
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(ОписаниеСохраненного.Объект);
			// АПК:1327-вкл.
		КонецЦикла;
		Для Каждого Строка Из ТаблицаИмен Цикл
			Если Не ЗначениеЗаполнено(Строка.Имя)
			 Или Не ЗначениеЗаполнено(Строка.ИмяРодителя) Тогда
				Продолжить;
			КонецЕсли;
			СтрокаРодителя = ОписаниеСохраненногоОбъекта(ОписаниеСохраненных.ТаблицаИмен, Строка.ИмяРодителя);
			Если СтрокаРодителя <> Неопределено Тогда
				НовыйОбъект = Строка.Ссылка.ПолучитьОбъект();
				НовыйОбъект.Родитель = СтрокаРодителя.Ссылка;
				// АПК:1327-выкл - №648.1.1 В вызывающей процедуре установлена исключительная блокировка.
				ОбновлениеИнформационнойБазы.ЗаписатьДанные(НовыйОбъект);
				// АПК:1327-вкл.
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Для Каждого ПолноеИмя Из ТаблицыБезСохраненных Цикл
		Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя);
		Менеджер.УстановитьИнициализациюПредопределенныхДанных(Ложь);
	КонецЦикла;
	
	ИнициализироватьПредопределенныеДанные();
	
КонецПроцедуры

// Возвращаемое значение:
//  СтрокаТаблицыЗначений:
//    * Ссылка - СправочникСсылка,
//             - ПланВидовХарактеристикСсылка
//             - ПланСчетовСсылка
//             - ПланВидовРасчетаСсылка
//    * Имя - Строка
//    * ВерсияДанных- Строка
//    * ИмяРодителя - Строка
//    * Объект - СправочникОбъект
//             - ПланВидовХарактеристикОбъект
//             - ПланСчетовОбъект
//             - ПланВидовРасчетаОбъект
//    * ОбъектСуществует - Булево
//  Неопределено
//
Функция ОписаниеСохраненногоОбъекта(ТаблицаИмен, ИмяРодителя)
	Возврат ТаблицаИмен.Найти(ИмяРодителя, "Имя");
КонецФункции

// Параметры:
//  СтарыйОбъект - ПланСчетовОбъект
//
Процедура ОбновитьОбъектСчета(СтарыйОбъект)
	
	НовыйОбъект = СтарыйОбъект.Ссылка.ПолучитьОбъект();
	НовыйОбъект.ИмяПредопределенныхДанных = СтарыйОбъект.ИмяПредопределенныхДанных;
	Для Каждого СтрокаВидаСубконто Из СтарыйОбъект.ВидыСубконто Цикл
		Если СтрокаВидаСубконто.Предопределенное Тогда
			НоваяСтрокаВидаСубконто = НовыйОбъект.ВидыСубконто.Найти(
				СтрокаВидаСубконто.ВидСубконто, "ВидСубконто");
			Если НоваяСтрокаВидаСубконто <> Неопределено Тогда
				НоваяСтрокаВидаСубконто.Предопределенное = Истина;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	СтарыйОбъект = НовыйОбъект;
	
КонецПроцедуры

// Параметры:
//  Счет - ПланСчетовОбъект
//  ОбразецСчета - ПланСчетовОбъект
// 
Процедура ДополнитьНовыеВидыСубконтоСчета(Счет, ОбразецСчета)
	
	Для Каждого Строка Из ОбразецСчета.ВидыСубконто Цикл
		Индекс = ОбразецСчета.ВидыСубконто.Индекс(Строка);
		Если Счет.ВидыСубконто.Количество() > Индекс Тогда
			Если Счет.ВидыСубконто[Индекс].ВидСубконто <> Строка.ВидСубконто Тогда
				ЗаписьЖурналаРегистрации(
					НСтр("ru = 'Обмен данными.Отключение связи с главным узлом'",
						ОбщегоНазначения.КодОсновногоЯзыка()),
					УровеньЖурналаРегистрации.Ошибка,
					Счет.Метаданные(),
					Счет,
					СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'У счета ""%1"" субконто №%2 ""%3"" не совпадает с предопределенным субконто ""%4"".'"),
						Строка(Счет),
						Индекс + 1,
						Строка(Счет.ВидыСубконто[Индекс].ВидСубконто),
						Строка(Строка.ВидСубконто)),
					РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная);
			ИначеЕсли Не Счет.ВидыСубконто[Индекс].Предопределенное Тогда
				Счет.ВидыСубконто[Индекс].Предопределенное = Истина;
			КонецЕсли;
		Иначе
			ЗаполнитьЗначенияСвойств(Счет.ВидыСубконто.Добавить(), Строка);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Процедура СохранитьСуществующиеПредопределенныеОбъектыПередСозданиемНедостающих(
		ОбъектМетаданных, ПолноеИмя, ТаблицаИмен, Имена, Запрос, ОписанияСохраненных, ТаблицыБезСохраненных)
	
	ТребуетсяИнициализация = Ложь;
	ПредопределенныеСуществуют = Ложь;
	ТаблицаИмен.Колонки.Добавить("ОбъектСуществует", Новый ОписаниеТипов("Булево"));
	
	Для Каждого Имя Из Имена Цикл
		Строки = ТаблицаИмен.НайтиСтроки(Новый Структура("Имя", Имя));
		Если Строки.Количество() = 0 Тогда
			ТребуетсяИнициализация = Истина;
		Иначе
			Для Каждого Строка Из Строки Цикл
				Строка.ОбъектСуществует = Истина;
			КонецЦикла;
			ПредопределенныеСуществуют = Истина;
		КонецЕсли;
	КонецЦикла;
	
	Если Не ТребуетсяИнициализация Тогда
		Возврат;
	КонецЕсли;
	
	Если ПредопределенныеСуществуют Тогда
		ЭтоПланСчетов = Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных);
		ОписаниеСохраненных = Новый Структура;
		ОписаниеСохраненных.Вставить("ПолноеИмя",     ПолноеИмя);
		ОписаниеСохраненных.Вставить("ТекстЗапроса",  Запрос.Текст);
		ОписаниеСохраненных.Вставить("ТаблицаИмен",   ТаблицаИмен);
		ОписаниеСохраненных.Вставить("ЭтоПланСчетов", ЭтоПланСчетов);
		ОписанияСохраненных.Добавить(ОписаниеСохраненных);
		
		ТаблицаИмен.Колонки.Добавить("Объект");
		Для Каждого Строка Из ТаблицаИмен Цикл
			Объект = Строка.Ссылка.ПолучитьОбъект();
			Объект.ИмяПредопределенныхДанных = "";
			Если ЭтоПланСчетов Тогда
				СтрокиПредопределенныхВидовСубконто = Новый Массив;
				Для Каждого СтрокаВидаСубконто Из Объект.ВидыСубконто Цикл
					Если СтрокаВидаСубконто.Предопределенное Тогда
						СтрокаВидаСубконто.Предопределенное = Ложь;
						СтрокиПредопределенныхВидовСубконто.Добавить(СтрокаВидаСубконто);
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
			// АПК:1327-выкл - №648.1.1 В вызывающей процедуре установлена исключительная блокировка.
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект);
			// АПК:1327-вкл.
			Если ЭтоПланСчетов Тогда
				Для Каждого СтрокаВидаСубконто Из СтрокиПредопределенныхВидовСубконто Цикл
					СтрокаВидаСубконто.Предопределенное = Истина;
				КонецЦикла;
			КонецЕсли;
			Если Строка.ОбъектСуществует Тогда
				Объект.ИмяПредопределенныхДанных = Строка.Имя;
			КонецЕсли;
			Строка.Объект = Объект;
		КонецЦикла;
	Иначе
		ТаблицыБезСохраненных.Добавить(ПолноеИмя);
	КонецЕсли;
	
КонецПроцедуры

Процедура ПередЗапускомПрограммы()
	
	// Привилегированный режим предустановлен платформой.
	
	Если ДлительныеОперации.ПропуститьОбработчикПередЗапускомПрограммы() Тогда
		Возврат;
	КонецЕсли;
	
	// Проверка основного языка программирования, установленного в конфигурации.
	ТекущийЯзыкВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка["Русский"];
	Если Метаданные.ВариантВстроенногоЯзыка <> ТекущийЯзыкВстроенногоЯзыка Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Вариант встроенного языка конфигурации ""%1"" не поддерживается.
			           |Используйте вариант языка ""%2"".'"),
			Метаданные.ВариантВстроенногоЯзыка,
			Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка["Русский"]);
	КонецЕсли;
	
	// Проверка настройки совместимости конфигурации с версией платформы.
	СистемнаяИнформация = Новый СистемнаяИнформация;
	ТекущаяВерсияПлатформы = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения);
	МинимальнаяВерсияПлатформы = ОбщегоНазначения.МинимальнаяВерсияПлатформы();
	
	НомераСборок = СтрРазделить(МинимальнаяВерсияПлатформы, "; ", Ложь);
	МинимальныйНомерСборкиДляТекущейВерсииПлатформы = НомераСборок[НомераСборок.ВГраница()];
	
	Для Каждого НомерСборки Из НомераСборок Цикл
		Если СтрНачинаетсяС(НомерСборки, ТекущаяВерсияПлатформы + ".") Тогда
			МинимальныйНомерСборкиДляТекущейВерсииПлатформы = НомерСборки;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, МинимальныйНомерСборкиДляТекущейВерсииПлатформы) < 0 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для запуска необходима версия платформы 1С:Предприятие %1 или выше.'"), МинимальныйНомерСборкиДляТекущейВерсииПлатформы);
	КонецЕсли;
	
	ПоддерживаемыеВерсииПлатформы = ОбщегоНазначения.ПоддерживаемыеВерсииПлатформы();
	ПоддерживаемаяВерсияПлатформы = ПоддерживаемыеВерсииПлатформы[ПоддерживаемыеВерсииПлатформы.Количество() - 1].Значение;
	ВерсияРежимаСовместимости = ОбщегоНазначения.ВерсияРежимаСовместимости();
	
	Если ПоддерживаемыеВерсииПлатформы.НайтиПоЗначению(ВерсияРежимаСовместимости) = Неопределено Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Режим совместимости конфигурации с 1С:Предприятием версии %1 не поддерживается.
			           |Для запуска установите в конфигурации режим совместимости ""Не использовать"" при разработке на версии %2
			           |(или ""Версия %2"" при разработке на более старших версиях).'"),
			ВерсияРежимаСовместимости, ПоддерживаемаяВерсияПлатформы);
	КонецЕсли;
	
	// Проверка заполнения версии конфигурации.
	Если ПустаяСтрока(Метаданные.Версия) Тогда
		ВызватьИсключение НСтр("ru = 'Не заполнено свойство конфигурации Версия.'");
	Иначе
		Попытка
			НулеваяВерсия = ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Метаданные.Версия, "0.0.0.0") = 0;
		Исключение
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Неправильно заполнено свойство конфигурации Версия: ""%1"".
				           |Правильный формат, например: ""1.2.3.45"".'"),
				Метаданные.Версия);
		КонецПопытки;
		Если НулеваяВерсия Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Неправильно заполнено свойство конфигурации Версия: ""%1"".
				           |Версия не может быть нулевой.'"),
				Метаданные.Версия);
		КонецЕсли;
	КонецЕсли;
	
	Если Не Метаданные.ОсновныеРоли.Содержит(Метаданные.Роли.АдминистраторСистемы)
	 Или Не Метаданные.ОсновныеРоли.Содержит(Метаданные.Роли.ПолныеПрава) Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В конфигурации в свойстве %1 не указаны стандартные роли %2 и %3.'"),
			"ОсновныеРоли", Метаданные.Роли.АдминистраторСистемы.Имя, Метаданные.Роли.ПолныеПрава.Имя);
	КонецЕсли;
	
	// Проверка возможности выполнения обработчиков установки параметров сеанса для запуска программы.
	ПроверитьВозможностьЗапуска();
	
	Если Не ЗначениеЗаполнено(ПользователиИнформационнойБазы.ТекущийПользователь().Имя)
	   И (Не ОбщегоНазначения.РазделениеВключено()
	      Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных())
	   И ОбновлениеИнформационнойБазыСлужебный.ВерсияИБ("СтандартныеПодсистемы",
	       ОбщегоНазначения.РазделениеВключено()) = "0.0.0.0" Тогда
		
		ПользователиСлужебный.УстановитьНачальныеНастройки("");
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПередЗапускомПрограммы();
	ОбщегоНазначенияПереопределяемый.ПередЗапускомПрограммы();
	
	СкорректироватьНачальнуюСтраницуНеразделенногоПользователя();
	ОбработатьОчередьСкопированныхНастроек();
	
КонецПроцедуры

// Для процедуры ПередЗапускомПрограммы.
Процедура СкорректироватьНачальнуюСтраницуНеразделенногоПользователя()
	
	Если ТекущийРежимЗапуска() = Неопределено
	 Или Не ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		СеансЗапущенБезРазделителей = МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей();
	Иначе
		СеансЗапущенБезРазделителей = Ложь;
	КонецЕсли;
	
	Если Не СеансЗапущенБезРазделителей Тогда
		Возврат;
	КонецЕсли;
	
	КлючОбъекта  = "БазоваяФункциональность";
	КлючНастроек = "СоставФормНачальнойСтраницыВМетаданных";
	
	ПредыдущийСоставФормВМетаданных = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта, КлючНастроек);
	Если ПредыдущийСоставФормВМетаданных = Неопределено Тогда
		// Очистка начальной страницы при первом входе.
		УстановитьПустуюФормуНаРабочийСтол();
	Иначе
		УстановитьПустуюФормуНаПустойРабочийСтол();
	КонецЕсли;
	
	// Компенсация изменения состава форм в метаданных начальной страницы.
	НовыеНастройки = Новый НастройкиНачальнойСтраницы;
	СоставФормВМетаданных = НовыеНастройки.ПолучитьСоставФорм();
	
	Если ТипЗнч(ПредыдущийСоставФормВМетаданных) <> Тип("Структура")
	 Или Не ПредыдущийСоставФормВМетаданных.Свойство("ЛеваяКолонка")
	 Или ТипЗнч(ПредыдущийСоставФормВМетаданных.ЛеваяКолонка) <> Тип("Массив")
	 Или Не ПредыдущийСоставФормВМетаданных.Свойство("ПраваяКолонка")
	 Или ТипЗнч(ПредыдущийСоставФормВМетаданных.ПраваяКолонка) <> Тип("Массив") Тогда
		
		ПредыдущийСоставФормВМетаданных = Новый СоставФормНачальнойСтраницы;
		
	ИначеЕсли СоставФормСовпадает(ПредыдущийСоставФормВМетаданных.ЛеваяКолонка,  СоставФормВМетаданных.ЛеваяКолонка)
	        И СоставФормСовпадает(ПредыдущийСоставФормВМетаданных.ПраваяКолонка, СоставФормВМетаданных.ПраваяКолонка) Тогда
		
		// Состав форм в метаданных начальной страницы не изменился.
		Возврат;
	КонецЕсли;
	
	КомпенсироватьИзмененияСоставаФормВМетаданныхНачальнойСтраницы(ПредыдущийСоставФормВМетаданных);
	
	СохраняемыйСоставФормВМетаданных = Новый Структура("ЛеваяКолонка, ПраваяКолонка");
	ЗаполнитьЗначенияСвойств(СохраняемыйСоставФормВМетаданных, СоставФормВМетаданных);
	
	ХранилищеОбщихНастроек.Сохранить(КлючОбъекта, КлючНастроек, СохраняемыйСоставФормВМетаданных);
	
КонецПроцедуры

// Для процедуры СкорректироватьНачальнуюСтраницуНеразделенногоПользователя.
Функция СоставФормСовпадает(ПредыдущиеФормыВМетаданных, ФормыВМетаданных)
	
	Если ПредыдущиеФормыВМетаданных.Количество() <> ФормыВМетаданных.Количество() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Для Каждого ИмяФормы Из ФормыВМетаданных Цикл
		Если ПредыдущиеФормыВМетаданных.Найти(ИмяФормы) = Неопределено Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

// Для процедуры СкорректироватьНачальнуюСтраницуНеразделенногоПользователя.
Процедура КомпенсироватьИзмененияСоставаФормВМетаданныхНачальнойСтраницы(ПредыдущийСоставФормВМетаданных)
	
	// При компенсации учитывается, что настройки начальной страницы могут
	// быть сохранены в рамках процедуры скрытия рабочего стола.
	
	КлючОбъекта         = "Общее/НастройкиНачальнойСтраницы";
	КлючОбъектаХранения = "Общее/НастройкиНачальнойСтраницыПередОчисткой";
	СохраненныеНастройки = ХранилищеСистемныхНастроек.Загрузить(КлючОбъектаХранения, "");
	НастройкиСохранены   = ТипЗнч(СохраненныеНастройки) = Тип("ХранилищеЗначения");
	
	Если НастройкиСохранены Тогда
		ТекущиеНастройки = СохраненныеНастройки.Получить();
	Иначе
		ТекущиеНастройки = ХранилищеСистемныхНастроек.Загрузить(КлючОбъекта);
	КонецЕсли;
	Если ТипЗнч(ТекущиеНастройки) = Тип("НастройкиНачальнойСтраницы") Тогда
		СоставФорм = ТекущиеНастройки.ПолучитьСоставФорм();
	Иначе
		СоставФорм = Новый СоставФормНачальнойСтраницы;
	КонецЕсли;
	
	НовыеНастройки = Новый НастройкиНачальнойСтраницы;
	СоставФормВМетаданных = НовыеНастройки.ПолучитьСоставФорм();
	
	УдалитьНовыеФормыНачальнойСтраницы(СоставФорм.ЛеваяКолонка,
		ПредыдущийСоставФормВМетаданных.ЛеваяКолонка, СоставФормВМетаданных.ЛеваяКолонка);
	
	УдалитьНовыеФормыНачальнойСтраницы(СоставФорм.ПраваяКолонка,
		ПредыдущийСоставФормВМетаданных.ПраваяКолонка, СоставФормВМетаданных.ПраваяКолонка);
	
	ТекущиеНастройки = Новый НастройкиНачальнойСтраницы;
	ТекущиеНастройки.УстановитьСоставФорм(СоставФорм);
	
	Если НастройкиСохранены Тогда
		СохраняемыеНастройки = Новый ХранилищеЗначения(ТекущиеНастройки);
		ХранилищеСистемныхНастроек.Сохранить(КлючОбъектаХранения, "", СохраняемыеНастройки);
		УстановитьПустуюФормуНаРабочийСтол();
	Иначе
		ХранилищеСистемныхНастроек.Сохранить(КлючОбъекта, "", ТекущиеНастройки);
	КонецЕсли;
	
КонецПроцедуры

// Для процедуры КомпенсироватьИзмененияСоставаФормВМетаданныхНачальнойСтраницы.
Процедура УдалитьНовыеФормыНачальнойСтраницы(ТекущиеФормы, ПредыдущиеФормыВМетаданных, ФормыВМетаданных)
	
	Для Каждого ИмяФормы Из ФормыВМетаданных Цикл
		Если ПредыдущиеФормыВМетаданных.Найти(ИмяФормы) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Индекс = ТекущиеФормы.Найти(ИмяФормы);
		Если Индекс <> Неопределено Тогда
			ТекущиеФормы.Удалить(Индекс);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Процедура ОбработатьОчередьСкопированныхНастроек()
	
	Если ТекущийРежимЗапуска() = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ОчередьНастроек = ХранилищеОбщихНастроек.Загрузить("ОчередьНастроек", "НеПримененныеНастройки");
	Если ТипЗнч(ОчередьНастроек) <> Тип("ХранилищеЗначения") Тогда
		Возврат;
	КонецЕсли;
	ОчередьНастроек = ОчередьНастроек.Получить();
	Если ТипЗнч(ОчередьНастроек) <> Тип("Соответствие") Тогда
		Возврат;
	КонецЕсли;
	
	Для Каждого ЭлементОчереди Из ОчередьНастроек Цикл
		Попытка
			Настройка = ХранилищеСистемныхНастроек.Загрузить(ЭлементОчереди.Ключ, ЭлементОчереди.Значение);
		Исключение
			Продолжить;
		КонецПопытки;
		ХранилищеСистемныхНастроек.Сохранить(ЭлементОчереди.Ключ, ЭлементОчереди.Значение, Настройка);
	КонецЦикла;
	
	ХранилищеОбщихНастроек.Сохранить("ОчередьНастроек", "НеПримененныеНастройки", Неопределено);
	
КонецПроцедуры

Процедура ВыполнитьОбработчикиУстановкиПараметровСеанса(ИменаПараметровСеанса, Обработчики, УстановленныеПараметры)
	
	// Массив с ключами параметров сеанса
	// задаются начальным словом в имени параметра сеанса и символом "*".
	ПараметрыСеансаКлючи = Новый Массив;
	
	Для Каждого Запись Из Обработчики Цикл
		Если СтрНайти(Запись.Ключ, "*") > 0 Тогда
			КлючПараметра = СокрЛП(Запись.Ключ);
			ПараметрыСеансаКлючи.Добавить(Лев(КлючПараметра, СтрДлина(КлючПараметра)-1));
		КонецЕсли;
	КонецЦикла;
	
	Для каждого ИмяПараметра Из ИменаПараметровСеанса Цикл
		Если УстановленныеПараметры.Найти(ИмяПараметра) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Обработчик = Обработчики.Получить(ИмяПараметра);
		Если Обработчик <> Неопределено Тогда
			ПараметрыОбработчика = Новый Массив();
			ПараметрыОбработчика.Добавить(ИмяПараметра);
			ПараметрыОбработчика.Добавить(УстановленныеПараметры);
			ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик, ПараметрыОбработчика);
			Продолжить;
		КонецЕсли;
		
		Для Каждого ИмяКлючаПараметра Из ПараметрыСеансаКлючи Цикл
			Если СтрНачинаетсяС(ИмяПараметра, ИмяКлючаПараметра) Тогда
				Обработчик = Обработчики.Получить(ИмяКлючаПараметра + "*");
				ПараметрыОбработчика = Новый Массив();
				ПараметрыОбработчика.Добавить(ИмяПараметра);
				ПараметрыОбработчика.Добавить(УстановленныеПараметры);
				ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик, ПараметрыОбработчика);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

Процедура ИгнорироватьОтправкуИдентификаторовОбъектовМетаданных(ЭлементДанных, ОтправкаЭлемента, Знач СозданиеНачальногоОбраза = Ложь)
	
	Если Не СозданиеНачальногоОбраза
		И ОбъектМетаданных(ЭлементДанных) = Метаданные.Справочники.ИдентификаторыОбъектовМетаданных Тогда
		
		ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ИгнорироватьПолучениеИдентификаторовОбъектовМетаданных(ЭлементДанных, ПолучениеЭлемента)
	
	Если ОбъектМетаданных(ЭлементДанных) = Метаданные.Справочники.ИдентификаторыОбъектовМетаданных Тогда
		ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
	КонецЕсли;
	
КонецПроцедуры

Функция ОбъектМетаданных(Знач ЭлементДанных)
	
	Возврат ?(ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта"), ЭлементДанных.Ссылка.Метаданные(), ЭлементДанных.Метаданные());
	
КонецФункции

Функция СозданиеНачальногоОбраза(Знач ЭлементДанных)
	
	Возврат ?(ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта"), Ложь, ЭлементДанных.ДополнительныеСвойства.Свойство("СозданиеНачальногоОбраза"));
	
КонецФункции

Функция ПоказатьНерекомендуемуюВерсиюПлатформы(Параметры)
	
	Если Параметры.РазделениеВключено Тогда
		Возврат Ложь;
	КонецЕсли;
	
	// Проверка, что пользователь не внешний.
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ИдентификаторПользователяИБ",
		ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор);
	
	Запрос.Текст = 
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	ИСТИНА КАК ЗначениеИстина
	|ИЗ
	|	Справочник.ВнешниеПользователи КАК ВнешниеПользователи
	|ГДЕ
	|	ВнешниеПользователи.ИдентификаторПользователяИБ = &ИдентификаторПользователяИБ";
	
	Если НЕ Запрос.Выполнить().Пустой() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	Текущая       = СистемнаяИнформация.ВерсияПриложения;
	Минимальная   = Параметры.МинимальнаяВерсияПлатформы;
	Рекомендуемая = Параметры.РекомендуемаяВерсияПлатформы;
	
	Возврат ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Текущая, Минимальная) < 0
		Или ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Текущая, Рекомендуемая) < 0;
	
КонецФункции

Функция ПараметрыАдминистрированияПоУмолчанию()
	
	ПараметрыАдминистрированияКластера = АдминистрированиеКластера.ПараметрыАдминистрированияКластера();
	ПараметрыАдминистрированияИБ = АдминистрированиеКластера.ПараметрыАдминистрированияИнформационнойБазыКластера();
	
	// Объединяем структуры параметров.
	СтруктураПараметровАдминистрирования = ПараметрыАдминистрированияКластера;
	Для Каждого Элемент Из ПараметрыАдминистрированияИБ Цикл
		СтруктураПараметровАдминистрирования.Вставить(Элемент.Ключ, Элемент.Значение);
	КонецЦикла;
	
	СтруктураПараметровАдминистрирования.Вставить("ПринятоРешениеПоОткрытиюВнешнихОтчетовИОбработок", Ложь);
	
	Возврат СтруктураПараметровАдминистрирования;
	
КонецФункции

Процедура ПрочитатьПараметрыИзСтрокиСоединения(СтруктураПараметровАдминистрирования)
	
	ПодстрокиСтрокиСоединения = СтрРазделить(СтрокаСоединенияИнформационнойБазы(), ";");
	
	СтрокаИмениСервера = СтроковыеФункцииКлиентСервер.СократитьДвойныеКавычки(Сред(ПодстрокиСтрокиСоединения[0], 7));
	СтруктураПараметровАдминистрирования.ИмяВКластере = СтроковыеФункцииКлиентСервер.СократитьДвойныеКавычки(Сред(ПодстрокиСтрокиСоединения[1], 6));
	
	СписокСерверовКластера = СтрРазделить(СтрокаИмениСервера, ",");
	Если СписокСерверовКластера.Количество() = 1 Тогда 
		СписокСерверовКластера = СтрРазделить(СтрокаИмениСервера, ";");
	КонецЕсли;
	
	ИмяСервера = СписокСерверовКластера[0];
	
	// Протокол может быть только tcp. Можно отбросить.
	Если СтрНачинаетсяС(ВРег(ИмяСервера), "TCP://") Тогда
		ИмяСервера = Сред(ИмяСервера, 7);
	КонецЕсли;
	
	// Если в качестве имени сервера передается адрес IPv6, то порт может быть только после закрывающей квадратной скобки.
	НачальнаяПозиция = СтрНайти(ИмяСервера, "]");
	Если НачальнаяПозиция <> 0 Тогда
		РазделительПорта = СтрНайти(ИмяСервера, ":",, НачальнаяПозиция);
	Иначе
		РазделительПорта = СтрНайти(ИмяСервера, ":");
	КонецЕсли;
	
	Если РазделительПорта > 0 Тогда
		АдресАгентаСервера = Сред(ИмяСервера, 1, РазделительПорта - 1);
		ПортКластера = Число(Сред(ИмяСервера, РазделительПорта + 1));
		Если СтруктураПараметровАдминистрирования.ПортКластера = 1541 Тогда
			СтруктураПараметровАдминистрирования.ПортКластера = ПортКластера;
		КонецЕсли;
	Иначе
		АдресАгентаСервера = ИмяСервера;
	КонецЕсли;
	
	СтруктураПараметровАдминистрирования.АдресАгентаСервера = АдресАгентаСервера;
	
КонецПроцедуры

// Проверяет возможность выполнения обработчиков установки параметров сеанса, 
// обработчиков обновления и других базовых механизмов конфигурации, 
// выполняющих код конфигурации по полному имени процедуры.
//
// В случае, если при текущих настройках профилей безопасности (в кластере серверов и в информационной базе) 
// выполнение обработчиков невозможно - генерируется исключение,
// содержащее описание причины и перечень действий по ее устранению.
//
Процедура ПроверитьВозможностьЗапуска()
	
	Если ОбщегоНазначения.ИнформационнаяБазаФайловая(СтрокаСоединенияИнформационнойБазы()) Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
		МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
		ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы();
	Иначе
		ПрофильИнформационнойБазы = "";
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда
		
		// Информационная база настроена на использование с профилем безопасности, в котором запрещен
		// полный доступ к внешним модулям.
		
		УстановитьБезопасныйРежим(ПрофильИнформационнойБазы);
		Если БезопасныйРежим() <> ПрофильИнформационнойБазы Тогда
			
			// Профиль ИБ не доступен для выполнения обработчиков.
			
			УстановитьБезопасныйРежим(Ложь);
			
			Попытка
				ДоступенПривилегированныйРежим = ВозможноВыполнениеОбработчиковБезУстановкиБезопасногоРежима();
			Исключение
				ДоступенПривилегированныйРежим = Ложь;
			КонецПопытки;
				
			Если Не ДоступенПривилегированныйРежим Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Невозможно установить параметры сеанса по причине: профиль безопасности %1 отсутствует в кластере серверов 1С:Предприятия, или для него запрещено использование в качестве профиля безопасности безопасного режима.
						|
						|Для восстановления работоспособности программы отключите использование профиля безопасности через консоль кластера и заново настройте профили безопасности с помощью интерфейса конфигурации (соответствующие команды находятся в разделе настроек программы).'"),
					ПрофильИнформационнойБазы);
			КонецЕсли;
			
		КонецЕсли;
		
		ДоступенПривилегированныйРежим = ДоступенПереходВПривилегированныйРежим();
		
		УстановитьБезопасныйРежим(Ложь);
		
		Если Не ДоступенПривилегированныйРежим Тогда
			
			// Профиль ИБ доступен для выполнения обработчиков, но в нем невозможна установка привилегированного режима.
			
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Невозможно установить параметры сеанса по причине: профиль безопасности %1 не содержит разрешения на установку привилегированного режима. Возможно, он был отредактирован через консоль кластера.
					|
					|Для восстановления работоспособности программы отключите использование профиля безопасности через консоль кластера и заново настройте профили безопасности с помощью интерфейса конфигурации (соответствующие команды находятся в разделе настроек программы).'"),
				ПрофильИнформационнойБазы);
			
		КонецЕсли;
		
	Иначе
		
		// Информационная база не настроена на использование с профилем безопасности, в котором запрещен
		// полный доступ к внешним модулям.
		
		Попытка
			ДоступенПривилегированныйРежим = ВозможноВыполнениеОбработчиковБезУстановкиБезопасногоРежима();
		Исключение
			
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Невозможно установить параметры сеанса по причине: %1.
					|
					|Возможно, для информационной базы через консоль кластера был установлен профиль безопасности, не допускающий выполнения внешних модулей без установки безопасного режима. В этом случае для восстановления работоспособности программы отключите использование профиля безопасности через консоль кластера и заново настройте профили безопасности с помощью интерфейса конфигурации (соответствующие команды находятся в разделе настроек программы). При этом программа будет автоматически корректно настроена на использование совместно с включенными профилями безопасности.'"),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

// Проверяет возможность выполнения обработчиков без установки безопасного режима.
//
// Возвращаемое значение:
//   Булево
//
Функция ВозможноВыполнениеОбработчиковБезУстановкиБезопасногоРежима()
	
	// Вызов ОбщегоНазначения.ВычислитьВБезопасномРежиме не требуется,
	// т.к. это проверка установки привилегированного режима в функции Вычислить без установки безопасного режима.
	Возврат Вычислить("ДоступенПереходВПривилегированныйРежим()"); // АПК:488
		
КонецФункции

// Проверяет возможность перехода в привилегированный режим из текущего безопасного режима.
//
// Возвращаемое значение:
//   Булево
//
Функция ДоступенПереходВПривилегированныйРежим()
	
	УстановитьПривилегированныйРежим(Истина);
	Возврат ПривилегированныйРежим();
	
КонецФункции

// Для процедуры ЗарегистрироватьИзменениеПриоритетныхДанныхДляПодчиненныхУзловРИБ.
Процедура ЗарегистрироватьИзменениеПредопределенных(УзлыПлановОбменаРИБ, КоллекцияМетаданных)
	
	Запрос = Новый Запрос;
	
	Для Каждого ОбъектМетаданных Из КоллекцияМетаданных Цикл
		УзлыРИБ = Новый Массив;
		
		Для Каждого УзлыПланаОбмена Из УзлыПлановОбменаРИБ Цикл
			Если Не УзлыПланаОбмена.Ключ.Содержит(ОбъектМетаданных) Тогда
				Продолжить;
			КонецЕсли;
			Для Каждого УзелРИБ Из УзлыПланаОбмена.Значение Цикл
				УзлыРИБ.Добавить(УзелРИБ);
			КонецЦикла;
		КонецЦикла;
		
		Если УзлыРИБ.Количество() = 0 Тогда
			Продолжить;
		КонецЕсли;
		
		Запрос.Текст =
		"ВЫБРАТЬ
		|	ТекущаяТаблица.Ссылка КАК Ссылка
		|ИЗ
		|	&ТекущаяТаблица КАК ТекущаяТаблица
		|ГДЕ
		|	ТекущаяТаблица.Предопределенный";
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", ОбъектМетаданных.ПолноеИмя());
		// @skip-check query-in-loop - Порционная обработка данных
		Выборка = Запрос.Выполнить().Выбрать();
		
		Пока Выборка.Следующий() Цикл
			ПланыОбмена.ЗарегистрироватьИзменения(УзлыРИБ, Выборка.Ссылка);
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

// Для процедуры УстановитьКлючНазначенияФормы.
Процедура УстановитьКлючНазначенияИспользованияФормы(Форма, Ключ, УстановитьНастройки)
	
	Если Не ЗначениеЗаполнено(Ключ)
	 Или Форма.КлючНазначенияИспользования = Ключ Тогда
		
		Возврат;
	КонецЕсли;
	
	Если Не УстановитьНастройки Тогда
		Форма.КлючНазначенияИспользования = Ключ;
		Возврат;
	КонецЕсли;
	
	ТипыНастроек = Новый Массив;
	// Русский вариант.
	ТипыНастроек.Добавить("/КлючТекущегоВарианта");
	ТипыНастроек.Добавить("/КлючТекущихПользовательскихНастроек");
	ТипыНастроек.Добавить("/ТекущиеПользовательскиеНастройки");
	ТипыНастроек.Добавить("/КлючТекущихНастроекДанных");
	ТипыНастроек.Добавить("/ТекущиеДанные");
	ТипыНастроек.Добавить("/НастройкиФормы");
	// Английский вариант.
	ТипыНастроек.Добавить("/CurrentVariantKey");
	ТипыНастроек.Добавить("/CurrentUserSettingsKey");
	ТипыНастроек.Добавить("/CurrentUserSettings");
	ТипыНастроек.Добавить("/CurrentDataSettingsKey");
	ТипыНастроек.Добавить("/CurrentData");
	ТипыНастроек.Добавить("/FormSettings");
	Если ХранилищеСистемныхНастроек.Загрузить(Ключ, "КлючНазначенияИспользованияФормы") <> Истина 
		 И ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
		УстановитьНастройкиДляКлюча(Ключ, ТипыНастроек, Форма.ИмяФормы, Форма.КлючНазначенияИспользования);
		ХранилищеСистемныхНастроек.Сохранить(Ключ, "КлючНазначенияИспользованияФормы", Истина);
	КонецЕсли;
	
	Форма.КлючНазначенияИспользования = Ключ;
	
КонецПроцедуры

// Для процедуры УстановитьКлючНазначенияФормы.
Процедура УстановитьКлючСохраненияПоложенияОкнаФормы(Форма, Ключ, УстановитьНастройки)
	
	Если Не ЗначениеЗаполнено(Ключ)
	 Или Форма.КлючСохраненияПоложенияОкна = Ключ Тогда
		
		Возврат;
	КонецЕсли;
	
	Если Не УстановитьНастройки Тогда
		Форма.КлючСохраненияПоложенияОкна = Ключ;
		Возврат;
	КонецЕсли;
	
	ТипыНастроек = Новый Массив;
	// Русский вариант.
	ТипыНастроек.Добавить("/НастройкиОкнаТонкогоКлиента"); // @Non-NLS
	ТипыНастроек.Добавить("/Такси/НастройкиОкнаТонкогоКлиента"); // @Non-NLS
	ТипыНастроек.Добавить("/НастройкиОкнаВебКлиента"); // @Non-NLS
	ТипыНастроек.Добавить("/Такси/НастройкиОкнаВебКлиента"); // @Non-NLS
	// Английский вариант.
	ТипыНастроек.Добавить("/ThinClientWindowSettings");
	ТипыНастроек.Добавить("/Taxi/ThinClientWindowSettings");
	ТипыНастроек.Добавить("/WebClientWindowSettings");
	ТипыНастроек.Добавить("/Taxi/WebClientWindowSettings");
	
	Если ХранилищеСистемныхНастроек.Загрузить(Ключ, "КлючСохраненияПоложенияОкнаФормы") <> Истина 
		И ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
		УстановитьНастройкиДляКлюча(Ключ, ТипыНастроек, Форма.ИмяФормы, Форма.КлючСохраненияПоложенияОкна);
		ХранилищеСистемныхНастроек.Сохранить(Ключ, "КлючСохраненияПоложенияОкнаФормы", Истина);
	КонецЕсли;
	
	Форма.КлючСохраненияПоложенияОкна = Ключ;
	
КонецПроцедуры

// Для процедур УстановитьКлючНазначенияИспользованияФормы, УстановитьКлючСохраненияПоложенияОкнаФормы.
Процедура УстановитьНастройкиДляКлюча(Ключ, ТипыНастроек, ИмяФормы, ТекущийКлюч)
	
	Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
		Возврат;
	КонецЕсли;
	
	НовыйКлюч = "/" + Ключ;
	Отбор = Новый Структура;
	Отбор.Вставить("Пользователь", ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
	
	Для каждого ТипНастроек Из ТипыНастроек Цикл
		Отбор.Вставить("КлючОбъекта", ИмяФормы + НовыйКлюч + ТипНастроек);
		Выборка = ХранилищеСистемныхНастроек.Выбрать(Отбор);
		Если Выборка.Следующий() Тогда
			Возврат; // Настройки для ключа уже установлены.
		КонецЕсли;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(ТекущийКлюч) Тогда
		ТекущийКлюч = "/" + ТекущийКлюч;
	КонецЕсли;
	
	// Установка начальных настроек ключа копированием от текущего ключа.
	Для Каждого ТипНастроек Из ТипыНастроек Цикл
		Отбор.Вставить("КлючОбъекта", ИмяФормы + ТекущийКлюч + ТипНастроек);
		Выборка = ХранилищеСистемныхНастроек.Выбрать(Отбор);
		КлючОбъекта = ИмяФормы + НовыйКлюч + ТипНастроек;
		Пока Выборка.Следующий() Цикл
			ОписаниеНастроек = Новый ОписаниеНастроек;
			ОписаниеНастроек.Представление = Выборка.Представление;
			ХранилищеСистемныхНастроек.Сохранить(КлючОбъекта, Выборка.КлючНастроек,
				Выборка.Настройки, ОписаниеНастроек);
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

// Проверка и отправка серверных оповещений клиенту.

// См. ПриПериодическомПолученииДанныхКлиентаНаСервере
Процедура ПриПериодическойПроверкеИзмененаКонфигурацияИлиРасширения(СообщениеПользователю)
	
	
	УстановитьПривилегированныйРежим(Истина);
	
	ИмяПользователя = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
	
	МожноОповещать = ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммыДляПользователя(ИмяПользователя);
	Если Не МожноОповещать Тогда
		Возврат;
	КонецЕсли;
	
	ДатаНапомнитьЗавтра = ОбщегоНазначения.ХранилищеСистемныхНастроекЗагрузить(
		"КонтрольДинамическогоОбновления", "ДатаНапомнитьЗавтра",,, ИмяПользователя);
	
	Если ТипЗнч(ДатаНапомнитьЗавтра) = Тип("Дата")
	   И ТекущаяДатаСеанса() < ДатаНапомнитьЗавтра Тогда
		Возврат;
	КонецЕсли;
	
	КонфигурацияБазыДанныхИзмененаДинамически = КонфигурацияБазыДанныхИзмененаДинамически();
	ДинамическиеИзменения = Справочники.ВерсииРасширений.ДинамическиИзмененныеРасширения(
		Справочники.ВерсииРасширений.УстановленныеРасширенияПриЗапуске(), Истина);
	
	Если Не КонфигурацияБазыДанныхИзмененаДинамически
	   И Не ЗначениеЗаполнено(ДинамическиеИзменения.Расширения)
	   И Не ЗначениеЗаполнено(ДинамическиеИзменения.Исправления) Тогда
		Возврат;
	КонецЕсли;
	
	Если ДинамическиеИзменения.Исправления <> Неопределено
		И ДинамическиеИзменения.Расширения = Неопределено
		И Не КонфигурацияБазыДанныхИзмененаДинамически
		// Изменился только состав исправлений, необходимо проверить возможность отображения оповещения.
		И ДинамическиеИзменения.Исправления.Добавлено <> 0
		И ДинамическиеИзменения.Исправления.Удалено = 0 Тогда
	
		РасписаниеОповещения = ОбщегоНазначения.ХранилищеСистемныхНастроекЗагрузить(
			"КонтрольДинамическогоОбновления", "РасписаниеПроверкиПатчей",,, ИмяПользователя);
		
		Если ТипЗнч(РасписаниеОповещения) = Тип("Структура")
			И РасписаниеОповещения.Свойство("Расписание")
			И ТипЗнч(РасписаниеОповещения.Расписание) = Тип("РасписаниеРегламентногоЗадания") Тогда
			
			ТекущаяДатаСеанса = ТекущаяДатаСеанса();
			МожноОповещать = РасписаниеОповещения.Расписание.ТребуетсяВыполнение(ТекущаяДатаСеанса,
				РасписаниеОповещения.ПоследнееОповещение);
			
			Если МожноОповещать Тогда
				РасписаниеОповещения.ПоследнееОповещение = ТекущаяДатаСеанса;
				ОбщегоНазначения.ХранилищеСистемныхНастроекСохранить("КонтрольДинамическогоОбновления",
					"РасписаниеПроверкиПатчей", РасписаниеОповещения,, ИмяПользователя);
			КонецЕсли;
		Иначе 
			ОдинРазВДень = Новый РасписаниеРегламентногоЗадания;
			ОдинРазВДень.ПериодПовтораДней = 1;
			ОбщегоНазначения.ХранилищеСистемныхНастроекСохранить("КонтрольДинамическогоОбновления", "РасписаниеПроверкиПатчей", ОдинРазВДень);
		КонецЕсли;
	КонецЕсли;
	
	Если Не МожноОповещать Тогда
		Возврат;
	КонецЕсли;
	
	ДинамическиеИзменения.Вставить("КонфигурацияБазыДанныхИзмененаДинамически",
		КонфигурацияБазыДанныхИзмененаДинамически);
		
	Сообщения = Новый Массив;
	Сообщения.Добавить(ТекстСообщенияПриДинамическомОбновлении(ДинамическиеИзменения));
	Сообщения.Добавить(НСтр("ru = 'Нажмите здесь, чтобы применить или отложить применение исправлений.'"));
	СообщениеПользователю = СтрСоединить(Сообщения, Символы.ПС);
	
КонецПроцедуры

// См. ПриОтправкеСерверногоОповещения
Процедура ПриОтправкеСерверногоОповещенияФункциональныеОпцииИзменены(ИмяОповещения, ВариантыПараметров)
	
	ИмяПараметра = "СтандартныеПодсистемы.БазоваяФункциональность.ВключенныеФункциональныеОпции";
	СтароеЗначение = ПараметрРаботыРасширения(ИмяПараметра, Истина);
	
	НовыйСоставТипов = Новый Массив;
	ФункциональныеОпцииПоТипам = Новый Соответствие;
	Для Каждого ФункциональнаяОпция Из Метаданные.ФункциональныеОпции Цикл
		ОбъектХранения = ФункциональнаяОпция.Хранение;
		Если Не Метаданные.Константы.Содержит(ОбъектХранения) Тогда
			Продолжить;
		КонецЕсли;
		Тип = Тип("КонстантаМенеджер." + ОбъектХранения.Имя);
		ФункциональныеОпцииПоТипам.Вставить(Тип, ФункциональнаяОпция);
		Если ПолучитьФункциональнуюОпцию(ФункциональнаяОпция.Имя) = Истина Тогда
			НовыйСоставТипов.Добавить(Тип);
		КонецЕсли;
	КонецЦикла;
	НовоеЗначение = Новый ОписаниеТипов(НовыйСоставТипов);
	Если СтароеЗначение = НовоеЗначение Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(СтароеЗначение) = Тип("ОписаниеТипов") Тогда
		СоставИзмененийТипов = Новый Соответствие;
		Для Каждого Тип Из НовоеЗначение.Типы() Цикл
			СоставИзмененийТипов.Вставить(Тип, Истина);
		КонецЦикла;
		Для Каждого Тип Из СтароеЗначение.Типы() Цикл
			Если СоставИзмененийТипов.Получить(Тип) = Неопределено Тогда
				СоставИзмененийТипов.Вставить(Тип, Истина);
			Иначе
				СоставИзмененийТипов.Удалить(Тип);
			КонецЕсли;
		КонецЦикла;
		
		Объекты = Новый Соответствие;
		Для Каждого КлючИЗначение Из СоставИзмененийТипов Цикл
			ФункциональнаяОпция = ФункциональныеОпцииПоТипам.Получить(КлючИЗначение.Ключ);
			Если ФункциональнаяОпция = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ДобавитьОбъектыФункциональнойОпции(Объекты, ФункциональнаяОпция);
		КонецЦикла;
		
		Адресаты = Новый Соответствие;
		Для Каждого ВариантПараметров Из ВариантыПараметров Цикл
			Для Каждого Адресат Из ВариантПараметров.Адресаты Цикл
				ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(Адресат.Ключ);
				Если ПользовательИБ = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				Для Каждого КлючИЗначение Из Объекты Цикл
					Если ПравоДоступа(КлючИЗначение.Значение, КлючИЗначение.Ключ, ПользовательИБ) Тогда
						Адресаты.Вставить(Адресат.Ключ, Адресат.Значение);
						Прервать;
					КонецЕсли;
				КонецЦикла;
			КонецЦикла;
		КонецЦикла;
		Если ЗначениеЗаполнено(Адресаты) Тогда
			СерверныеОповещения.ОтправитьСерверноеОповещение(ИмяОповещения, "", Адресаты);
		КонецЕсли;
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений");
	ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка());
	ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		СтароеЗначение = ПараметрРаботыРасширения(ИмяПараметра, Истина);
		Если СтароеЗначение <> НовоеЗначение Тогда
			УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина);
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура ДобавитьОбъектыФункциональнойОпции(Объекты, ФункциональнаяОпция)
	
	ИменаБазовыхТипов =
	"
	|Подсистема
	|ОбщийРеквизит
	|ПланОбмена
	|КритерийОтбора
	|ОбщаяФорма
	|ОбщаяКоманда
	|Константа
	|Справочник
	|Документ
	|ЖурналДокументов
	|Отчет
	|Обработка
	|ПланВидовХарактеристик
	|ПланСчетов
	|ПланВидовРасчета
	|РегистрСведений
	|РегистрНакопления
	|РегистрБухгалтерии
	|РегистрРасчета
	|БизнесПроцесс
	|Задача
	|";
	
	Для Каждого ЭлементСостава Из ФункциональнаяОпция.Состав Цикл
		Объект = ЭлементСостава.Объект;
		Если Объекты.Получить(Объект) <> Неопределено
		 Или ТипЗнч(Объект) <> Тип("ОбъектМетаданных") Тогда
			Продолжить;
		КонецЕсли;
		Попытка
			ПолноеИмя = Объект.ПолноеИмя();
		Исключение
			ПолноеИмя = "";
		КонецПопытки;
		ЧастиИмени = СтрРазделить(ПолноеИмя, ".", Ложь);
		Если ЧастиИмени.Количество() < 2 Тогда
			Продолжить;
		КонецЕсли;
		ИмяБазовогоТипа = ЧастиИмени[0];
		Если СтрНайти(ИменаБазовыхТипов, Символы.ПС + ИмяБазовогоТипа + Символы.ПС) = 0 Тогда
			Продолжить;
		КонецЕсли;
		Если ЧастиИмени.Количество() > 2 Тогда
			Если ИмяБазовогоТипа <> "Подсистема" Тогда
				Объект = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ЧастиИмени[0] + "." + ЧастиИмени[1]);
				Если Объект = Неопределено
				 Или Объекты.Получить(Объект) <> Неопределено Тогда
					Продолжить;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		Объекты.Вставить(Объект, "Просмотр");
	КонецЦикла;
	
КонецПроцедуры

// Многоязычные конфигурации

Функция ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
		МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
		Возврат МодульМультиязычностьСервер.ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы();
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Другие процедуры и функции.

Функция ЭлементыСтиля() Экспорт
	
	НаборЭлементовСтиля = Новый Структура;
	Для каждого ЭлементСтиля Из Метаданные.ЭлементыСтиля Цикл
		НаборЭлементовСтиля.Вставить(ЭлементСтиля.Имя, ЭлементСтиля.Значение);
	КонецЦикла;
	
	Возврат Новый ФиксированнаяСтруктура(НаборЭлементовСтиля);
	
КонецФункции

// Возвращает сериализуемый набор элементов стиля.
// 
// Возвращаемое значение:
//  Структура:
//   * Ключ - Строка - имя элемента стиля.
//   * Значение - Строка
//              - ОбъектМетаданныхЭлементСтиля - элемент стиля. Для толстого клиента обычного приложения
//                           элемент стиля преобразуется в системное строковое представление переданного значения.
//
Функция НаборЭлементовСтиля()
	
	НаборЭлементовСтиля = Новый Структура;
	Для каждого ЭлементСтиля Из Метаданные.ЭлементыСтиля Цикл
		
		Если ТекущийРежимЗапуска() = РежимЗапускаКлиентскогоПриложения.ОбычноеПриложение Тогда
			НаборЭлементовСтиля.Вставить(ЭлементСтиля.Имя, Новый ХранилищеЗначения(ЭлементСтиля.Значение));
		Иначе
			НаборЭлементовСтиля.Вставить(ЭлементСтиля.Имя, ЭлементСтиля.Значение);
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Новый ФиксированнаяСтруктура(НаборЭлементовСтиля);
	
КонецФункции

// Для процедуры ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам.
Процедура ДобавитьЗапросРазрешенийНаИспользованиеРасширений(ЗапросыРазрешений)
	
	Если ОбщегоНазначения.РазделениеВключено()
	   И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		Возврат;
	КонецЕсли;
	
	Разрешения = Новый Массив;
	ВсеРасширения = РасширенияКонфигурации.Получить();
	
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	Для Каждого Расширение Из ВсеРасширения Цикл
		Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеВнешнегоМодуля(
			Расширение.Имя, Base64Строка(Расширение.ХешСумма)));
	КонецЦикла;
	
	ЗапросыРазрешений.Добавить(МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения,
		ОбщегоНазначения.ИдентификаторОбъектаМетаданных("РегистрСведений.ПараметрыРаботыВерсийРасширений")));

КонецПроцедуры

Функция ТребуетсяПоказРекомендацииПоОбъемуОперативнойПамяти()
	
	Если ОбщегоНазначения.ЭтоВебКлиент()
	 Или Не ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ОперативнаяПамять = ПараметрыКлиентаНаСервере().Получить("ОперативнаяПамять");
	Если ТипЗнч(ОперативнаяПамять) <> Тип("Число") Тогда
		Возврат Ложь; // Параметр клиента на сервере не заполнен (нет клиентского приложения).
	КонецЕсли;
	
	РекомендуемыйОбъем = ОбщегоНазначения.ОбщиеПараметрыБазовойФункциональности().РекомендуемыйОбъемОперативнойПамяти;
	СохраненнаяРекомендация = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить("ОбщиеНастройкиПользователя",
		"РекомендацияПоОбъемуОперативнойПамяти");
	
	Рекомендация = Новый Структура;
	Рекомендация.Вставить("Показывать", Истина);
	Рекомендация.Вставить("ДатаПредыдущегоПоказа", Дата(1, 1, 1));
	
	Если ТипЗнч(СохраненнаяРекомендация) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Рекомендация, СохраненнаяРекомендация);
	КонецЕсли;
	
	Возврат ОперативнаяПамять < РекомендуемыйОбъем
		И (Рекомендация.Показывать
		   Или (ТекущаяДатаСеанса() - Рекомендация.ДатаПредыдущегоПоказа) > 60*60*24*60)
	
КонецФункции

Процедура ИгнорироватьОтправкуДанныхОбработанныхВЦентральномУзлеРИБПриОбновленииИБ(ЭлементДанных, СозданиеНачальногоОбраза, Получатель)
	
	Если Получатель <> Неопределено
		И Не СозданиеНачальногоОбраза
		И ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ДанныеОбработанныеВЦентральномУзлеРИБ") Тогда
		
		Индекс = ЭлементДанных.Количество() - 1;
		Пока Индекс >= 0 Цикл
			СтрокаНабора = ЭлементДанных[Индекс];
			Если СтрокаНабора.УзелПланаОбмена <> Получатель Тогда
				ЭлементДанных.Удалить(СтрокаНабора);
			КонецЕсли;
			Индекс = Индекс - 1;
		КонецЦикла;
		
	КонецЕсли;

КонецПроцедуры

Функция ИспользуетсяНедопустимаяВерсияПлатформы()
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	НерекомендуемыеВерсииПлатформы = ОбщегоНазначения.НедопустимыеВерсииПлатформы();
	
	Возврат СтрНайти(НерекомендуемыеВерсииПлатформы, СистемнаяИнформация.ВерсияПриложения);
	
КонецФункции

#КонецОбласти

#КонецЕсли